allocationfilter_test.go 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783
  1. package kubecost
  2. import (
  3. "fmt"
  4. "reflect"
  5. "testing"
  6. )
  7. func Test_AllocationFilterCondition_Matches(t *testing.T) {
  8. cases := []struct {
  9. name string
  10. a *Allocation
  11. filter AllocationFilter
  12. expected bool
  13. }{
  14. {
  15. name: "ClusterID Equals -> true",
  16. a: &Allocation{
  17. Properties: &AllocationProperties{
  18. Cluster: "cluster-one",
  19. },
  20. },
  21. filter: AllocationFilterCondition{
  22. Field: FilterClusterID,
  23. Op: FilterEquals,
  24. Value: "cluster-one",
  25. },
  26. expected: true,
  27. },
  28. {
  29. name: "ClusterID StartsWith -> true",
  30. a: &Allocation{
  31. Properties: &AllocationProperties{
  32. Cluster: "cluster-one",
  33. },
  34. },
  35. filter: AllocationFilterCondition{
  36. Field: FilterClusterID,
  37. Op: FilterStartsWith,
  38. Value: "cluster",
  39. },
  40. expected: true,
  41. },
  42. {
  43. name: "ClusterID StartsWith -> false",
  44. a: &Allocation{
  45. Properties: &AllocationProperties{
  46. Cluster: "k8s-one",
  47. },
  48. },
  49. filter: AllocationFilterCondition{
  50. Field: FilterClusterID,
  51. Op: FilterStartsWith,
  52. Value: "cluster",
  53. },
  54. expected: false,
  55. },
  56. {
  57. name: "ClusterID empty StartsWith '' -> true",
  58. a: &Allocation{
  59. Properties: &AllocationProperties{
  60. Cluster: "",
  61. },
  62. },
  63. filter: AllocationFilterCondition{
  64. Field: FilterClusterID,
  65. Op: FilterStartsWith,
  66. Value: "",
  67. },
  68. expected: true,
  69. },
  70. {
  71. name: "ClusterID nonempty StartsWith '' -> true",
  72. a: &Allocation{
  73. Properties: &AllocationProperties{
  74. Cluster: "abc",
  75. },
  76. },
  77. filter: AllocationFilterCondition{
  78. Field: FilterClusterID,
  79. Op: FilterStartsWith,
  80. Value: "",
  81. },
  82. expected: true,
  83. },
  84. {
  85. name: "Node Equals -> true",
  86. a: &Allocation{
  87. Properties: &AllocationProperties{
  88. Node: "node123",
  89. },
  90. },
  91. filter: AllocationFilterCondition{
  92. Field: FilterNode,
  93. Op: FilterEquals,
  94. Value: "node123",
  95. },
  96. expected: true,
  97. },
  98. {
  99. name: "Namespace NotEquals -> false",
  100. a: &Allocation{
  101. Properties: &AllocationProperties{
  102. Namespace: "kube-system",
  103. },
  104. },
  105. filter: AllocationFilterCondition{
  106. Field: FilterNamespace,
  107. Op: FilterNotEquals,
  108. Value: "kube-system",
  109. },
  110. expected: false,
  111. },
  112. {
  113. name: "Namespace NotEquals Unallocated -> true",
  114. a: &Allocation{
  115. Properties: &AllocationProperties{
  116. Namespace: "kube-system",
  117. },
  118. },
  119. filter: AllocationFilterCondition{
  120. Field: FilterNamespace,
  121. Op: FilterNotEquals,
  122. Value: UnallocatedSuffix,
  123. },
  124. expected: true,
  125. },
  126. {
  127. name: "Namespace NotEquals Unallocated -> false",
  128. a: &Allocation{
  129. Properties: &AllocationProperties{
  130. Namespace: "",
  131. },
  132. },
  133. filter: AllocationFilterCondition{
  134. Field: FilterNamespace,
  135. Op: FilterNotEquals,
  136. Value: UnallocatedSuffix,
  137. },
  138. expected: false,
  139. },
  140. {
  141. name: "Namespace Equals Unallocated -> true",
  142. a: &Allocation{
  143. Properties: &AllocationProperties{
  144. Namespace: "",
  145. },
  146. },
  147. filter: AllocationFilterCondition{
  148. Field: FilterNamespace,
  149. Op: FilterEquals,
  150. Value: UnallocatedSuffix,
  151. },
  152. expected: true,
  153. },
  154. {
  155. name: "ControllerKind Equals -> true",
  156. a: &Allocation{
  157. Properties: &AllocationProperties{
  158. ControllerKind: "deployment", // We generally store controller kinds as all lowercase
  159. },
  160. },
  161. filter: AllocationFilterCondition{
  162. Field: FilterControllerKind,
  163. Op: FilterEquals,
  164. Value: "deployment",
  165. },
  166. expected: true,
  167. },
  168. {
  169. name: "ControllerName Equals -> true",
  170. a: &Allocation{
  171. Properties: &AllocationProperties{
  172. Controller: "kc-cost-analyzer",
  173. },
  174. },
  175. filter: AllocationFilterCondition{
  176. Field: FilterControllerName,
  177. Op: FilterEquals,
  178. Value: "kc-cost-analyzer",
  179. },
  180. expected: true,
  181. },
  182. {
  183. name: "Pod (with UID) Equals -> true",
  184. a: &Allocation{
  185. Properties: &AllocationProperties{
  186. Pod: "pod-123 UID-ABC",
  187. },
  188. },
  189. filter: AllocationFilterCondition{
  190. Field: FilterPod,
  191. Op: FilterEquals,
  192. Value: "pod-123 UID-ABC",
  193. },
  194. expected: true,
  195. },
  196. {
  197. name: "Container Equals -> true",
  198. a: &Allocation{
  199. Properties: &AllocationProperties{
  200. Container: "cost-model",
  201. },
  202. },
  203. filter: AllocationFilterCondition{
  204. Field: FilterContainer,
  205. Op: FilterEquals,
  206. Value: "cost-model",
  207. },
  208. expected: true,
  209. },
  210. {
  211. name: `label[app]="foo" -> true`,
  212. a: &Allocation{
  213. Properties: &AllocationProperties{
  214. Labels: map[string]string{
  215. "app": "foo",
  216. },
  217. },
  218. },
  219. filter: AllocationFilterCondition{
  220. Field: FilterLabel,
  221. Op: FilterEquals,
  222. Key: "app",
  223. Value: "foo",
  224. },
  225. expected: true,
  226. },
  227. {
  228. name: `label[app]="foo" -> different value -> false`,
  229. a: &Allocation{
  230. Properties: &AllocationProperties{
  231. Labels: map[string]string{
  232. "app": "bar",
  233. },
  234. },
  235. },
  236. filter: AllocationFilterCondition{
  237. Field: FilterLabel,
  238. Op: FilterEquals,
  239. Key: "app",
  240. Value: "foo",
  241. },
  242. expected: false,
  243. },
  244. {
  245. name: `label[app]="foo" -> label missing -> false`,
  246. a: &Allocation{
  247. Properties: &AllocationProperties{
  248. Labels: map[string]string{
  249. "someotherlabel": "someothervalue",
  250. },
  251. },
  252. },
  253. filter: AllocationFilterCondition{
  254. Field: FilterLabel,
  255. Op: FilterEquals,
  256. Key: "app",
  257. Value: "foo",
  258. },
  259. expected: false,
  260. },
  261. {
  262. name: `label[app]=Unallocated -> label missing -> true`,
  263. a: &Allocation{
  264. Properties: &AllocationProperties{
  265. Labels: map[string]string{
  266. "someotherlabel": "someothervalue",
  267. },
  268. },
  269. },
  270. filter: AllocationFilterCondition{
  271. Field: FilterLabel,
  272. Op: FilterEquals,
  273. Key: "app",
  274. Value: UnallocatedSuffix,
  275. },
  276. expected: true,
  277. },
  278. {
  279. name: `label[app]=Unallocated -> label present -> false`,
  280. a: &Allocation{
  281. Properties: &AllocationProperties{
  282. Labels: map[string]string{
  283. "app": "test",
  284. },
  285. },
  286. },
  287. filter: AllocationFilterCondition{
  288. Field: FilterLabel,
  289. Op: FilterEquals,
  290. Key: "app",
  291. Value: UnallocatedSuffix,
  292. },
  293. expected: false,
  294. },
  295. {
  296. name: `label[app]!=Unallocated -> label missing -> false`,
  297. a: &Allocation{
  298. Properties: &AllocationProperties{
  299. Labels: map[string]string{
  300. "someotherlabel": "someothervalue",
  301. },
  302. },
  303. },
  304. filter: AllocationFilterCondition{
  305. Field: FilterLabel,
  306. Op: FilterNotEquals,
  307. Key: "app",
  308. Value: UnallocatedSuffix,
  309. },
  310. expected: false,
  311. },
  312. {
  313. name: `label[app]!=Unallocated -> label present -> true`,
  314. a: &Allocation{
  315. Properties: &AllocationProperties{
  316. Labels: map[string]string{
  317. "app": "test",
  318. },
  319. },
  320. },
  321. filter: AllocationFilterCondition{
  322. Field: FilterLabel,
  323. Op: FilterNotEquals,
  324. Key: "app",
  325. Value: UnallocatedSuffix,
  326. },
  327. expected: true,
  328. },
  329. {
  330. name: `label[app]!="foo" -> label missing -> true`,
  331. a: &Allocation{
  332. Properties: &AllocationProperties{
  333. Labels: map[string]string{
  334. "someotherlabel": "someothervalue",
  335. },
  336. },
  337. },
  338. filter: AllocationFilterCondition{
  339. Field: FilterLabel,
  340. Op: FilterNotEquals,
  341. Key: "app",
  342. Value: "foo",
  343. },
  344. expected: true,
  345. },
  346. {
  347. name: `annotation[prom_modified_name]="testing123" -> true`,
  348. a: &Allocation{
  349. Properties: &AllocationProperties{
  350. Annotations: map[string]string{
  351. "prom_modified_name": "testing123",
  352. },
  353. },
  354. },
  355. filter: AllocationFilterCondition{
  356. Field: FilterAnnotation,
  357. Op: FilterEquals,
  358. Key: "prom_modified_name",
  359. Value: "testing123",
  360. },
  361. expected: true,
  362. },
  363. {
  364. name: `annotation[app]="foo" -> different value -> false`,
  365. a: &Allocation{
  366. Properties: &AllocationProperties{
  367. Annotations: map[string]string{
  368. "app": "bar",
  369. },
  370. },
  371. },
  372. filter: AllocationFilterCondition{
  373. Field: FilterAnnotation,
  374. Op: FilterEquals,
  375. Key: "app",
  376. Value: "foo",
  377. },
  378. expected: false,
  379. },
  380. {
  381. name: `annotation[app]="foo" -> annotation missing -> false`,
  382. a: &Allocation{
  383. Properties: &AllocationProperties{
  384. Annotations: map[string]string{
  385. "someotherannotation": "someothervalue",
  386. },
  387. },
  388. },
  389. filter: AllocationFilterCondition{
  390. Field: FilterAnnotation,
  391. Op: FilterEquals,
  392. Key: "app",
  393. Value: "foo",
  394. },
  395. expected: false,
  396. },
  397. {
  398. name: `annotation[app]!="foo" -> annotation missing -> true`,
  399. a: &Allocation{
  400. Properties: &AllocationProperties{
  401. Annotations: map[string]string{
  402. "someotherannotation": "someothervalue",
  403. },
  404. },
  405. },
  406. filter: AllocationFilterCondition{
  407. Field: FilterAnnotation,
  408. Op: FilterNotEquals,
  409. Key: "app",
  410. Value: "foo",
  411. },
  412. expected: true,
  413. },
  414. {
  415. name: `namespace unallocated -> true`,
  416. a: &Allocation{
  417. Properties: &AllocationProperties{
  418. Namespace: "",
  419. },
  420. },
  421. filter: AllocationFilterCondition{
  422. Field: FilterNamespace,
  423. Op: FilterEquals,
  424. Value: UnallocatedSuffix,
  425. },
  426. expected: true,
  427. },
  428. {
  429. name: `services contains -> true`,
  430. a: &Allocation{
  431. Properties: &AllocationProperties{
  432. Services: []string{"serv1", "serv2"},
  433. },
  434. },
  435. filter: AllocationFilterCondition{
  436. Field: FilterServices,
  437. Op: FilterContains,
  438. Value: "serv2",
  439. },
  440. expected: true,
  441. },
  442. {
  443. name: `services contains -> false`,
  444. a: &Allocation{
  445. Properties: &AllocationProperties{
  446. Services: []string{"serv1", "serv2"},
  447. },
  448. },
  449. filter: AllocationFilterCondition{
  450. Field: FilterServices,
  451. Op: FilterContains,
  452. Value: "serv3",
  453. },
  454. expected: false,
  455. },
  456. {
  457. name: `services notcontains -> true`,
  458. a: &Allocation{
  459. Properties: &AllocationProperties{
  460. Services: []string{"serv1", "serv2"},
  461. },
  462. },
  463. filter: AllocationFilterCondition{
  464. Field: FilterServices,
  465. Op: FilterNotContains,
  466. Value: "serv3",
  467. },
  468. expected: true,
  469. },
  470. {
  471. name: `services notcontains -> false`,
  472. a: &Allocation{
  473. Properties: &AllocationProperties{
  474. Services: []string{"serv1", "serv2"},
  475. },
  476. },
  477. filter: AllocationFilterCondition{
  478. Field: FilterServices,
  479. Op: FilterNotContains,
  480. Value: "serv2",
  481. },
  482. expected: false,
  483. },
  484. {
  485. name: `services notcontains unallocated -> true`,
  486. a: &Allocation{
  487. Properties: &AllocationProperties{
  488. Services: []string{"serv1", "serv2"},
  489. },
  490. },
  491. filter: AllocationFilterCondition{
  492. Field: FilterServices,
  493. Op: FilterNotContains,
  494. Value: UnallocatedSuffix,
  495. },
  496. expected: true,
  497. },
  498. {
  499. name: `services notcontains unallocated -> false`,
  500. a: &Allocation{
  501. Properties: &AllocationProperties{
  502. Services: []string{},
  503. },
  504. },
  505. filter: AllocationFilterCondition{
  506. Field: FilterServices,
  507. Op: FilterNotContains,
  508. Value: UnallocatedSuffix,
  509. },
  510. expected: false,
  511. },
  512. {
  513. name: `services containsprefix -> true`,
  514. a: &Allocation{
  515. Properties: &AllocationProperties{
  516. Services: []string{"serv1", "serv2"},
  517. },
  518. },
  519. filter: AllocationFilterCondition{
  520. Field: FilterServices,
  521. Op: FilterContainsPrefix,
  522. Value: "serv",
  523. },
  524. expected: true,
  525. },
  526. {
  527. name: `services containsprefix -> false`,
  528. a: &Allocation{
  529. Properties: &AllocationProperties{
  530. Services: []string{"foo", "bar"},
  531. },
  532. },
  533. filter: AllocationFilterCondition{
  534. Field: FilterServices,
  535. Op: FilterContainsPrefix,
  536. Value: "serv",
  537. },
  538. expected: false,
  539. },
  540. {
  541. name: `services contains unallocated -> false`,
  542. a: &Allocation{
  543. Properties: &AllocationProperties{
  544. Services: []string{"serv1", "serv2"},
  545. },
  546. },
  547. filter: AllocationFilterCondition{
  548. Field: FilterServices,
  549. Op: FilterContains,
  550. Value: UnallocatedSuffix,
  551. },
  552. expected: false,
  553. },
  554. {
  555. name: `services contains unallocated -> true`,
  556. a: &Allocation{
  557. Properties: &AllocationProperties{
  558. Services: []string{},
  559. },
  560. },
  561. filter: AllocationFilterCondition{
  562. Field: FilterServices,
  563. Op: FilterContains,
  564. Value: UnallocatedSuffix,
  565. },
  566. expected: true,
  567. },
  568. }
  569. for _, c := range cases {
  570. result := c.filter.Matches(c.a)
  571. if result != c.expected {
  572. t.Errorf("%s: expected %t, got %t", c.name, c.expected, result)
  573. }
  574. }
  575. }
  576. func Test_AllocationFilterNone_Matches(t *testing.T) {
  577. cases := []struct {
  578. name string
  579. a *Allocation
  580. }{
  581. {
  582. name: "nil",
  583. a: nil,
  584. },
  585. {
  586. name: "nil properties",
  587. a: &Allocation{
  588. Properties: nil,
  589. },
  590. },
  591. {
  592. name: "empty properties",
  593. a: &Allocation{
  594. Properties: &AllocationProperties{},
  595. },
  596. },
  597. {
  598. name: "ClusterID",
  599. a: &Allocation{
  600. Properties: &AllocationProperties{
  601. Cluster: "cluster-one",
  602. },
  603. },
  604. },
  605. {
  606. name: "Node",
  607. a: &Allocation{
  608. Properties: &AllocationProperties{
  609. Node: "node123",
  610. },
  611. },
  612. },
  613. {
  614. name: "Namespace",
  615. a: &Allocation{
  616. Properties: &AllocationProperties{
  617. Namespace: "kube-system",
  618. },
  619. },
  620. },
  621. {
  622. name: "ControllerKind",
  623. a: &Allocation{
  624. Properties: &AllocationProperties{
  625. ControllerKind: "deployment", // We generally store controller kinds as all lowercase
  626. },
  627. },
  628. },
  629. {
  630. name: "ControllerName",
  631. a: &Allocation{
  632. Properties: &AllocationProperties{
  633. Controller: "kc-cost-analyzer",
  634. },
  635. },
  636. },
  637. {
  638. name: "Pod",
  639. a: &Allocation{
  640. Properties: &AllocationProperties{
  641. Pod: "pod-123 UID-ABC",
  642. },
  643. },
  644. },
  645. {
  646. name: "Container",
  647. a: &Allocation{
  648. Properties: &AllocationProperties{
  649. Container: "cost-model",
  650. },
  651. },
  652. },
  653. {
  654. name: `label`,
  655. a: &Allocation{
  656. Properties: &AllocationProperties{
  657. Labels: map[string]string{
  658. "app": "foo",
  659. },
  660. },
  661. },
  662. },
  663. {
  664. name: `annotation`,
  665. a: &Allocation{
  666. Properties: &AllocationProperties{
  667. Annotations: map[string]string{
  668. "prom_modified_name": "testing123",
  669. },
  670. },
  671. },
  672. },
  673. {
  674. name: `services`,
  675. a: &Allocation{
  676. Properties: &AllocationProperties{
  677. Services: []string{"serv1", "serv2"},
  678. },
  679. },
  680. },
  681. }
  682. for _, c := range cases {
  683. result := AllocationFilterNone{}.Matches(c.a)
  684. if result {
  685. t.Errorf("%s: should have been rejected", c.name)
  686. }
  687. }
  688. }
  689. func Test_AllocationFilterAnd_Matches(t *testing.T) {
  690. cases := []struct {
  691. name string
  692. a *Allocation
  693. filter AllocationFilter
  694. expected bool
  695. }{
  696. {
  697. name: `label[app]="foo" and namespace="kubecost" -> both true`,
  698. a: &Allocation{
  699. Properties: &AllocationProperties{
  700. Namespace: "kubecost",
  701. Labels: map[string]string{
  702. "app": "foo",
  703. },
  704. },
  705. },
  706. filter: AllocationFilterAnd{[]AllocationFilter{
  707. AllocationFilterCondition{
  708. Field: FilterLabel,
  709. Op: FilterEquals,
  710. Key: "app",
  711. Value: "foo",
  712. },
  713. AllocationFilterCondition{
  714. Field: FilterNamespace,
  715. Op: FilterEquals,
  716. Value: "kubecost",
  717. },
  718. }},
  719. expected: true,
  720. },
  721. {
  722. name: `label[app]="foo" and namespace="kubecost" -> first true`,
  723. a: &Allocation{
  724. Properties: &AllocationProperties{
  725. Namespace: "kube-system",
  726. Labels: map[string]string{
  727. "app": "foo",
  728. },
  729. },
  730. },
  731. filter: AllocationFilterAnd{[]AllocationFilter{
  732. AllocationFilterCondition{
  733. Field: FilterLabel,
  734. Op: FilterEquals,
  735. Key: "app",
  736. Value: "foo",
  737. },
  738. AllocationFilterCondition{
  739. Field: FilterNamespace,
  740. Op: FilterEquals,
  741. Value: "kubecost",
  742. },
  743. }},
  744. expected: false,
  745. },
  746. {
  747. name: `label[app]="foo" and namespace="kubecost" -> second true`,
  748. a: &Allocation{
  749. Properties: &AllocationProperties{
  750. Namespace: "kubecost",
  751. Labels: map[string]string{
  752. "app": "bar",
  753. },
  754. },
  755. },
  756. filter: AllocationFilterAnd{[]AllocationFilter{
  757. AllocationFilterCondition{
  758. Field: FilterLabel,
  759. Op: FilterEquals,
  760. Key: "app",
  761. Value: "foo",
  762. },
  763. AllocationFilterCondition{
  764. Field: FilterNamespace,
  765. Op: FilterEquals,
  766. Value: "kubecost",
  767. },
  768. }},
  769. expected: false,
  770. },
  771. {
  772. name: `label[app]="foo" and namespace="kubecost" -> both false`,
  773. a: &Allocation{
  774. Properties: &AllocationProperties{
  775. Namespace: "kube-system",
  776. Labels: map[string]string{
  777. "app": "bar",
  778. },
  779. },
  780. },
  781. filter: AllocationFilterAnd{[]AllocationFilter{
  782. AllocationFilterCondition{
  783. Field: FilterLabel,
  784. Op: FilterEquals,
  785. Key: "app",
  786. Value: "foo",
  787. },
  788. AllocationFilterCondition{
  789. Field: FilterNamespace,
  790. Op: FilterEquals,
  791. Value: "kubecost",
  792. },
  793. }},
  794. expected: false,
  795. },
  796. {
  797. name: `(and none) matches nothing`,
  798. a: &Allocation{
  799. Properties: &AllocationProperties{
  800. Namespace: "kube-system",
  801. Labels: map[string]string{
  802. "app": "bar",
  803. },
  804. },
  805. },
  806. filter: AllocationFilterAnd{[]AllocationFilter{
  807. AllocationFilterNone{},
  808. }},
  809. expected: false,
  810. },
  811. }
  812. for _, c := range cases {
  813. result := c.filter.Matches(c.a)
  814. if result != c.expected {
  815. t.Errorf("%s: expected %t, got %t", c.name, c.expected, result)
  816. }
  817. }
  818. }
  819. func Test_AllocationFilterOr_Matches(t *testing.T) {
  820. cases := []struct {
  821. name string
  822. a *Allocation
  823. filter AllocationFilter
  824. expected bool
  825. }{
  826. {
  827. name: `label[app]="foo" or namespace="kubecost" -> both true`,
  828. a: &Allocation{
  829. Properties: &AllocationProperties{
  830. Namespace: "kubecost",
  831. Labels: map[string]string{
  832. "app": "foo",
  833. },
  834. },
  835. },
  836. filter: AllocationFilterOr{[]AllocationFilter{
  837. AllocationFilterCondition{
  838. Field: FilterLabel,
  839. Op: FilterEquals,
  840. Key: "app",
  841. Value: "foo",
  842. },
  843. AllocationFilterCondition{
  844. Field: FilterNamespace,
  845. Op: FilterEquals,
  846. Value: "kubecost",
  847. },
  848. }},
  849. expected: true,
  850. },
  851. {
  852. name: `label[app]="foo" or namespace="kubecost" -> first true`,
  853. a: &Allocation{
  854. Properties: &AllocationProperties{
  855. Namespace: "kube-system",
  856. Labels: map[string]string{
  857. "app": "foo",
  858. },
  859. },
  860. },
  861. filter: AllocationFilterOr{[]AllocationFilter{
  862. AllocationFilterCondition{
  863. Field: FilterLabel,
  864. Op: FilterEquals,
  865. Key: "app",
  866. Value: "foo",
  867. },
  868. AllocationFilterCondition{
  869. Field: FilterNamespace,
  870. Op: FilterEquals,
  871. Value: "kubecost",
  872. },
  873. }},
  874. expected: true,
  875. },
  876. {
  877. name: `label[app]="foo" or namespace="kubecost" -> second true`,
  878. a: &Allocation{
  879. Properties: &AllocationProperties{
  880. Namespace: "kubecost",
  881. Labels: map[string]string{
  882. "app": "bar",
  883. },
  884. },
  885. },
  886. filter: AllocationFilterOr{[]AllocationFilter{
  887. AllocationFilterCondition{
  888. Field: FilterLabel,
  889. Op: FilterEquals,
  890. Key: "app",
  891. Value: "foo",
  892. },
  893. AllocationFilterCondition{
  894. Field: FilterNamespace,
  895. Op: FilterEquals,
  896. Value: "kubecost",
  897. },
  898. }},
  899. expected: true,
  900. },
  901. {
  902. name: `label[app]="foo" or namespace="kubecost" -> both false`,
  903. a: &Allocation{
  904. Properties: &AllocationProperties{
  905. Namespace: "kube-system",
  906. Labels: map[string]string{
  907. "app": "bar",
  908. },
  909. },
  910. },
  911. filter: AllocationFilterOr{[]AllocationFilter{
  912. AllocationFilterCondition{
  913. Field: FilterLabel,
  914. Op: FilterEquals,
  915. Key: "app",
  916. Value: "foo",
  917. },
  918. AllocationFilterCondition{
  919. Field: FilterNamespace,
  920. Op: FilterEquals,
  921. Value: "kubecost",
  922. },
  923. }},
  924. expected: false,
  925. },
  926. }
  927. for _, c := range cases {
  928. result := c.filter.Matches(c.a)
  929. if result != c.expected {
  930. t.Errorf("%s: expected %t, got %t", c.name, c.expected, result)
  931. }
  932. }
  933. }
  934. func Test_AllocationFilter_Flattened(t *testing.T) {
  935. cases := []struct {
  936. name string
  937. input AllocationFilter
  938. expected AllocationFilter
  939. }{
  940. {
  941. name: "AllocationFilterCondition",
  942. input: AllocationFilterCondition{
  943. Field: FilterNamespace,
  944. Op: FilterEquals,
  945. },
  946. expected: AllocationFilterCondition{
  947. Field: FilterNamespace,
  948. Op: FilterEquals,
  949. },
  950. },
  951. {
  952. name: "empty AllocationFilterAnd (nil)",
  953. input: AllocationFilterAnd{},
  954. expected: nil,
  955. },
  956. {
  957. name: "empty AllocationFilterAnd (len 0)",
  958. input: AllocationFilterAnd{Filters: []AllocationFilter{}},
  959. expected: nil,
  960. },
  961. {
  962. name: "empty AllocationFilterOr (nil)",
  963. input: AllocationFilterOr{},
  964. expected: nil,
  965. },
  966. {
  967. name: "empty AllocationFilterOr (len 0)",
  968. input: AllocationFilterOr{Filters: []AllocationFilter{}},
  969. expected: nil,
  970. },
  971. {
  972. name: "single-element AllocationFilterAnd",
  973. input: AllocationFilterAnd{Filters: []AllocationFilter{
  974. AllocationFilterCondition{
  975. Field: FilterNamespace,
  976. Op: FilterEquals,
  977. },
  978. }},
  979. expected: AllocationFilterCondition{
  980. Field: FilterNamespace,
  981. Op: FilterEquals,
  982. },
  983. },
  984. {
  985. name: "single-element AllocationFilterOr",
  986. input: AllocationFilterOr{Filters: []AllocationFilter{
  987. AllocationFilterCondition{
  988. Field: FilterNamespace,
  989. Op: FilterEquals,
  990. },
  991. }},
  992. expected: AllocationFilterCondition{
  993. Field: FilterNamespace,
  994. Op: FilterEquals,
  995. },
  996. },
  997. {
  998. name: "multi-element AllocationFilterAnd",
  999. input: AllocationFilterAnd{Filters: []AllocationFilter{
  1000. AllocationFilterCondition{
  1001. Field: FilterNamespace,
  1002. Op: FilterEquals,
  1003. },
  1004. AllocationFilterCondition{
  1005. Field: FilterClusterID,
  1006. Op: FilterNotEquals,
  1007. },
  1008. AllocationFilterCondition{
  1009. Field: FilterServices,
  1010. Op: FilterContains,
  1011. },
  1012. }},
  1013. expected: AllocationFilterAnd{Filters: []AllocationFilter{
  1014. AllocationFilterCondition{
  1015. Field: FilterNamespace,
  1016. Op: FilterEquals,
  1017. },
  1018. AllocationFilterCondition{
  1019. Field: FilterClusterID,
  1020. Op: FilterNotEquals,
  1021. },
  1022. AllocationFilterCondition{
  1023. Field: FilterServices,
  1024. Op: FilterContains,
  1025. },
  1026. }},
  1027. },
  1028. {
  1029. name: "multi-element AllocationFilterOr",
  1030. input: AllocationFilterOr{Filters: []AllocationFilter{
  1031. AllocationFilterCondition{
  1032. Field: FilterNamespace,
  1033. Op: FilterEquals,
  1034. },
  1035. AllocationFilterCondition{
  1036. Field: FilterClusterID,
  1037. Op: FilterNotEquals,
  1038. },
  1039. AllocationFilterCondition{
  1040. Field: FilterServices,
  1041. Op: FilterContains,
  1042. },
  1043. }},
  1044. expected: AllocationFilterOr{Filters: []AllocationFilter{
  1045. AllocationFilterCondition{
  1046. Field: FilterNamespace,
  1047. Op: FilterEquals,
  1048. },
  1049. AllocationFilterCondition{
  1050. Field: FilterClusterID,
  1051. Op: FilterNotEquals,
  1052. },
  1053. AllocationFilterCondition{
  1054. Field: FilterServices,
  1055. Op: FilterContains,
  1056. },
  1057. }},
  1058. },
  1059. {
  1060. name: "AllocationFilterNone",
  1061. input: AllocationFilterNone{},
  1062. expected: AllocationFilterNone{},
  1063. },
  1064. }
  1065. for _, c := range cases {
  1066. t.Run(c.name, func(t *testing.T) {
  1067. result := c.input.Flattened()
  1068. if !reflect.DeepEqual(result, c.expected) {
  1069. t.Errorf("Expected: '%s'. Got '%s'.", c.expected, result)
  1070. }
  1071. })
  1072. }
  1073. }
  1074. func Test_AllocationFilter_Equals(t *testing.T) {
  1075. cases := []struct {
  1076. left AllocationFilter
  1077. right AllocationFilter
  1078. expected bool
  1079. }{
  1080. // AFC
  1081. {
  1082. left: AllocationFilterCondition{},
  1083. right: AllocationFilterCondition{},
  1084. expected: true,
  1085. },
  1086. {
  1087. left: AllocationFilterCondition{
  1088. Field: FilterNamespace,
  1089. Op: FilterStartsWith,
  1090. Value: "kubecost-abc",
  1091. },
  1092. right: AllocationFilterCondition{
  1093. Field: FilterNamespace,
  1094. Op: FilterStartsWith,
  1095. Value: "kubecost-abc",
  1096. },
  1097. expected: true,
  1098. },
  1099. {
  1100. left: AllocationFilterCondition{
  1101. Field: FilterLabel,
  1102. Op: FilterEquals,
  1103. Key: "app",
  1104. Value: "kubecost-abc",
  1105. },
  1106. right: AllocationFilterCondition{
  1107. Field: FilterLabel,
  1108. Op: FilterEquals,
  1109. Key: "app",
  1110. Value: "kubecost-abc",
  1111. },
  1112. expected: true,
  1113. },
  1114. {
  1115. left: AllocationFilterCondition{
  1116. Field: FilterLabel,
  1117. Op: FilterEquals,
  1118. Key: "app",
  1119. Value: "kubecost-abc",
  1120. },
  1121. right: AllocationFilterCondition{
  1122. Field: FilterLabel,
  1123. Op: FilterEquals,
  1124. Value: "kubecost-abc",
  1125. },
  1126. expected: false,
  1127. },
  1128. {
  1129. left: AllocationFilterCondition{
  1130. Field: FilterLabel,
  1131. Op: FilterEquals,
  1132. Value: "kubecost-abc",
  1133. },
  1134. right: AllocationFilterCondition{
  1135. Field: FilterLabel,
  1136. Op: FilterEquals,
  1137. Key: "app",
  1138. Value: "kubecost-abc",
  1139. },
  1140. expected: false,
  1141. },
  1142. {
  1143. left: AllocationFilterCondition{
  1144. Field: FilterNamespace,
  1145. Op: FilterStartsWith,
  1146. Value: "kubecost-abc",
  1147. },
  1148. right: AllocationFilterCondition{
  1149. Field: FilterNamespace,
  1150. Op: FilterStartsWith,
  1151. Value: "kubecost-abcd",
  1152. },
  1153. expected: false,
  1154. },
  1155. // OR
  1156. // EMPTY
  1157. {
  1158. left: AllocationFilterOr{},
  1159. right: nil,
  1160. expected: false,
  1161. },
  1162. {
  1163. left: AllocationFilterOr{Filters: []AllocationFilter{}},
  1164. right: nil,
  1165. expected: false,
  1166. },
  1167. {
  1168. left: AllocationFilterOr{},
  1169. right: AllocationFilterOr{},
  1170. expected: true,
  1171. },
  1172. {
  1173. left: AllocationFilterOr{},
  1174. right: AllocationFilterOr{Filters: []AllocationFilter{}},
  1175. expected: true,
  1176. },
  1177. {
  1178. left: AllocationFilterOr{Filters: []AllocationFilter{}},
  1179. right: AllocationFilterOr{},
  1180. expected: true,
  1181. },
  1182. {
  1183. left: AllocationFilterOr{Filters: []AllocationFilter{}},
  1184. right: AllocationFilterOr{Filters: []AllocationFilter{}},
  1185. expected: true,
  1186. },
  1187. // FILLED
  1188. {
  1189. left: AllocationFilterOr{Filters: []AllocationFilter{
  1190. AllocationFilterNone{},
  1191. AllocationFilterCondition{
  1192. Field: FilterLabel,
  1193. Op: FilterStartsWith,
  1194. Key: "xyz",
  1195. Value: "kubecost",
  1196. },
  1197. AllocationFilterAnd{
  1198. Filters: []AllocationFilter{
  1199. AllocationFilterCondition{
  1200. Field: FilterNamespace,
  1201. Op: FilterEquals,
  1202. Value: "ns1",
  1203. },
  1204. AllocationFilterCondition{
  1205. Field: FilterNamespace,
  1206. Op: FilterEquals,
  1207. Value: "ns2",
  1208. },
  1209. },
  1210. },
  1211. }},
  1212. right: AllocationFilterOr{Filters: []AllocationFilter{
  1213. AllocationFilterNone{},
  1214. AllocationFilterCondition{
  1215. Field: FilterLabel,
  1216. Op: FilterStartsWith,
  1217. Key: "xyz",
  1218. Value: "kubecost",
  1219. },
  1220. AllocationFilterAnd{
  1221. Filters: []AllocationFilter{
  1222. AllocationFilterCondition{
  1223. Field: FilterNamespace,
  1224. Op: FilterEquals,
  1225. Value: "ns1",
  1226. },
  1227. AllocationFilterCondition{
  1228. Field: FilterNamespace,
  1229. Op: FilterEquals,
  1230. Value: "ns2",
  1231. },
  1232. },
  1233. },
  1234. }},
  1235. expected: true,
  1236. },
  1237. {
  1238. left: AllocationFilterOr{Filters: []AllocationFilter{
  1239. AllocationFilterNone{},
  1240. AllocationFilterCondition{
  1241. Field: FilterLabel,
  1242. Op: FilterStartsWith,
  1243. Key: "xyz",
  1244. Value: "kubecost",
  1245. },
  1246. AllocationFilterAnd{
  1247. Filters: []AllocationFilter{
  1248. AllocationFilterCondition{
  1249. Field: FilterNamespace,
  1250. Op: FilterEquals,
  1251. Value: "ns1",
  1252. },
  1253. AllocationFilterCondition{
  1254. Field: FilterNamespace,
  1255. Op: FilterEquals,
  1256. Value: "ns2",
  1257. },
  1258. },
  1259. },
  1260. }},
  1261. right: AllocationFilterOr{Filters: []AllocationFilter{
  1262. AllocationFilterCondition{
  1263. Field: FilterLabel,
  1264. Op: FilterStartsWith,
  1265. Key: "xyz",
  1266. Value: "kubecost",
  1267. },
  1268. AllocationFilterNone{},
  1269. AllocationFilterAnd{
  1270. Filters: []AllocationFilter{
  1271. AllocationFilterCondition{
  1272. Field: FilterNamespace,
  1273. Op: FilterEquals,
  1274. Value: "ns2",
  1275. },
  1276. AllocationFilterCondition{
  1277. Field: FilterNamespace,
  1278. Op: FilterEquals,
  1279. Value: "ns1",
  1280. },
  1281. },
  1282. },
  1283. }},
  1284. expected: true,
  1285. },
  1286. {
  1287. left: AllocationFilterOr{Filters: []AllocationFilter{
  1288. AllocationFilterNone{},
  1289. AllocationFilterCondition{
  1290. Field: FilterLabel,
  1291. Op: FilterStartsWith,
  1292. Key: "xyz",
  1293. Value: "kubecost",
  1294. },
  1295. AllocationFilterAnd{
  1296. Filters: []AllocationFilter{
  1297. AllocationFilterCondition{
  1298. Field: FilterNamespace,
  1299. Op: FilterEquals,
  1300. Value: "ns1",
  1301. },
  1302. AllocationFilterCondition{
  1303. Field: FilterNamespace,
  1304. Op: FilterEquals,
  1305. Value: "ns2",
  1306. },
  1307. },
  1308. },
  1309. }},
  1310. right: AllocationFilterOr{Filters: []AllocationFilter{
  1311. AllocationFilterAnd{
  1312. Filters: []AllocationFilter{
  1313. AllocationFilterCondition{
  1314. Field: FilterNamespace,
  1315. Op: FilterEquals,
  1316. Value: "ns1",
  1317. },
  1318. AllocationFilterCondition{
  1319. Field: FilterNamespace,
  1320. Op: FilterEquals,
  1321. Value: "ns2",
  1322. },
  1323. },
  1324. },
  1325. AllocationFilterNone{},
  1326. AllocationFilterCondition{
  1327. Field: FilterLabel,
  1328. Op: FilterStartsWith,
  1329. Key: "xyz",
  1330. Value: "kubecost",
  1331. },
  1332. }},
  1333. expected: true,
  1334. },
  1335. {
  1336. left: AllocationFilterOr{Filters: []AllocationFilter{
  1337. AllocationFilterNone{},
  1338. AllocationFilterCondition{
  1339. Field: FilterLabel,
  1340. Op: FilterStartsWith,
  1341. Key: "xyz",
  1342. Value: "kubecost",
  1343. },
  1344. AllocationFilterAnd{
  1345. Filters: []AllocationFilter{
  1346. AllocationFilterCondition{
  1347. Field: FilterNamespace,
  1348. Op: FilterEquals,
  1349. Value: "ns1",
  1350. },
  1351. AllocationFilterCondition{
  1352. Field: FilterNamespace,
  1353. Op: FilterEquals,
  1354. Value: "ns2",
  1355. },
  1356. },
  1357. },
  1358. }},
  1359. right: AllocationFilterOr{Filters: []AllocationFilter{
  1360. AllocationFilterNone{},
  1361. AllocationFilterCondition{
  1362. Field: FilterLabel,
  1363. Op: FilterStartsWith,
  1364. Key: "xyz",
  1365. Value: "kubecost",
  1366. },
  1367. AllocationFilterAnd{
  1368. Filters: []AllocationFilter{
  1369. AllocationFilterCondition{
  1370. Field: FilterNamespace,
  1371. Op: FilterEquals,
  1372. Value: "ns3",
  1373. },
  1374. AllocationFilterCondition{
  1375. Field: FilterNamespace,
  1376. Op: FilterEquals,
  1377. Value: "ns2",
  1378. },
  1379. },
  1380. },
  1381. }},
  1382. expected: false,
  1383. },
  1384. {
  1385. left: AllocationFilterOr{Filters: []AllocationFilter{
  1386. AllocationFilterNone{},
  1387. AllocationFilterCondition{
  1388. Field: FilterLabel,
  1389. Op: FilterStartsWith,
  1390. Key: "xyz",
  1391. Value: "kubecost",
  1392. },
  1393. AllocationFilterAnd{
  1394. Filters: []AllocationFilter{
  1395. AllocationFilterCondition{
  1396. Field: FilterNamespace,
  1397. Op: FilterEquals,
  1398. Value: "ns1",
  1399. },
  1400. AllocationFilterCondition{
  1401. Field: FilterNamespace,
  1402. Op: FilterEquals,
  1403. Value: "ns2",
  1404. },
  1405. },
  1406. },
  1407. }},
  1408. right: AllocationFilterOr{Filters: []AllocationFilter{
  1409. AllocationFilterCondition{
  1410. Field: FilterLabel,
  1411. Op: FilterStartsWith,
  1412. Key: "xyz",
  1413. Value: "kubecost",
  1414. },
  1415. AllocationFilterAnd{
  1416. Filters: []AllocationFilter{
  1417. AllocationFilterCondition{
  1418. Field: FilterNamespace,
  1419. Op: FilterEquals,
  1420. Value: "ns1",
  1421. },
  1422. AllocationFilterCondition{
  1423. Field: FilterNamespace,
  1424. Op: FilterEquals,
  1425. Value: "ns2",
  1426. },
  1427. },
  1428. },
  1429. }},
  1430. expected: false,
  1431. },
  1432. // AND
  1433. // EMPTY
  1434. {
  1435. left: AllocationFilterAnd{},
  1436. right: nil,
  1437. expected: false,
  1438. },
  1439. {
  1440. left: AllocationFilterAnd{Filters: []AllocationFilter{}},
  1441. right: nil,
  1442. expected: false,
  1443. },
  1444. {
  1445. left: AllocationFilterAnd{},
  1446. right: AllocationFilterAnd{},
  1447. expected: true,
  1448. },
  1449. {
  1450. left: AllocationFilterAnd{},
  1451. right: AllocationFilterAnd{Filters: []AllocationFilter{}},
  1452. expected: true,
  1453. },
  1454. {
  1455. left: AllocationFilterAnd{Filters: []AllocationFilter{}},
  1456. right: AllocationFilterAnd{},
  1457. expected: true,
  1458. },
  1459. {
  1460. left: AllocationFilterAnd{Filters: []AllocationFilter{}},
  1461. right: AllocationFilterAnd{Filters: []AllocationFilter{}},
  1462. expected: true,
  1463. },
  1464. // FILLED
  1465. {
  1466. left: AllocationFilterAnd{Filters: []AllocationFilter{
  1467. AllocationFilterNone{},
  1468. AllocationFilterCondition{
  1469. Field: FilterLabel,
  1470. Op: FilterStartsWith,
  1471. Key: "xyz",
  1472. Value: "kubecost",
  1473. },
  1474. AllocationFilterOr{
  1475. Filters: []AllocationFilter{
  1476. AllocationFilterCondition{
  1477. Field: FilterNamespace,
  1478. Op: FilterEquals,
  1479. Value: "ns1",
  1480. },
  1481. AllocationFilterCondition{
  1482. Field: FilterNamespace,
  1483. Op: FilterEquals,
  1484. Value: "ns2",
  1485. },
  1486. },
  1487. },
  1488. }},
  1489. right: AllocationFilterAnd{Filters: []AllocationFilter{
  1490. AllocationFilterNone{},
  1491. AllocationFilterCondition{
  1492. Field: FilterLabel,
  1493. Op: FilterStartsWith,
  1494. Key: "xyz",
  1495. Value: "kubecost",
  1496. },
  1497. AllocationFilterOr{
  1498. Filters: []AllocationFilter{
  1499. AllocationFilterCondition{
  1500. Field: FilterNamespace,
  1501. Op: FilterEquals,
  1502. Value: "ns1",
  1503. },
  1504. AllocationFilterCondition{
  1505. Field: FilterNamespace,
  1506. Op: FilterEquals,
  1507. Value: "ns2",
  1508. },
  1509. },
  1510. },
  1511. }},
  1512. expected: true,
  1513. },
  1514. {
  1515. left: AllocationFilterAnd{Filters: []AllocationFilter{
  1516. AllocationFilterNone{},
  1517. AllocationFilterCondition{
  1518. Field: FilterLabel,
  1519. Op: FilterStartsWith,
  1520. Key: "xyz",
  1521. Value: "kubecost",
  1522. },
  1523. AllocationFilterOr{
  1524. Filters: []AllocationFilter{
  1525. AllocationFilterCondition{
  1526. Field: FilterNamespace,
  1527. Op: FilterEquals,
  1528. Value: "ns1",
  1529. },
  1530. AllocationFilterCondition{
  1531. Field: FilterNamespace,
  1532. Op: FilterEquals,
  1533. Value: "ns2",
  1534. },
  1535. },
  1536. },
  1537. }},
  1538. right: AllocationFilterAnd{Filters: []AllocationFilter{
  1539. AllocationFilterCondition{
  1540. Field: FilterLabel,
  1541. Op: FilterStartsWith,
  1542. Key: "xyz",
  1543. Value: "kubecost",
  1544. },
  1545. AllocationFilterNone{},
  1546. AllocationFilterOr{
  1547. Filters: []AllocationFilter{
  1548. AllocationFilterCondition{
  1549. Field: FilterNamespace,
  1550. Op: FilterEquals,
  1551. Value: "ns2",
  1552. },
  1553. AllocationFilterCondition{
  1554. Field: FilterNamespace,
  1555. Op: FilterEquals,
  1556. Value: "ns1",
  1557. },
  1558. },
  1559. },
  1560. }},
  1561. expected: true,
  1562. },
  1563. {
  1564. left: AllocationFilterAnd{Filters: []AllocationFilter{
  1565. AllocationFilterNone{},
  1566. AllocationFilterCondition{
  1567. Field: FilterLabel,
  1568. Op: FilterStartsWith,
  1569. Key: "xyz",
  1570. Value: "kubecost",
  1571. },
  1572. AllocationFilterOr{
  1573. Filters: []AllocationFilter{
  1574. AllocationFilterCondition{
  1575. Field: FilterNamespace,
  1576. Op: FilterEquals,
  1577. Value: "ns1",
  1578. },
  1579. AllocationFilterCondition{
  1580. Field: FilterNamespace,
  1581. Op: FilterEquals,
  1582. Value: "ns2",
  1583. },
  1584. },
  1585. },
  1586. }},
  1587. right: AllocationFilterAnd{Filters: []AllocationFilter{
  1588. AllocationFilterOr{
  1589. Filters: []AllocationFilter{
  1590. AllocationFilterCondition{
  1591. Field: FilterNamespace,
  1592. Op: FilterEquals,
  1593. Value: "ns1",
  1594. },
  1595. AllocationFilterCondition{
  1596. Field: FilterNamespace,
  1597. Op: FilterEquals,
  1598. Value: "ns2",
  1599. },
  1600. },
  1601. },
  1602. AllocationFilterNone{},
  1603. AllocationFilterCondition{
  1604. Field: FilterLabel,
  1605. Op: FilterStartsWith,
  1606. Key: "xyz",
  1607. Value: "kubecost",
  1608. },
  1609. }},
  1610. expected: true,
  1611. },
  1612. {
  1613. left: AllocationFilterAnd{Filters: []AllocationFilter{
  1614. AllocationFilterNone{},
  1615. AllocationFilterCondition{
  1616. Field: FilterLabel,
  1617. Op: FilterStartsWith,
  1618. Key: "xyz",
  1619. Value: "kubecost",
  1620. },
  1621. AllocationFilterOr{
  1622. Filters: []AllocationFilter{
  1623. AllocationFilterCondition{
  1624. Field: FilterNamespace,
  1625. Op: FilterEquals,
  1626. Value: "ns1",
  1627. },
  1628. AllocationFilterCondition{
  1629. Field: FilterNamespace,
  1630. Op: FilterEquals,
  1631. Value: "ns2",
  1632. },
  1633. },
  1634. },
  1635. }},
  1636. right: AllocationFilterAnd{Filters: []AllocationFilter{
  1637. AllocationFilterNone{},
  1638. AllocationFilterCondition{
  1639. Field: FilterLabel,
  1640. Op: FilterStartsWith,
  1641. Key: "xyz",
  1642. Value: "kubecost",
  1643. },
  1644. AllocationFilterOr{
  1645. Filters: []AllocationFilter{
  1646. AllocationFilterCondition{
  1647. Field: FilterNamespace,
  1648. Op: FilterEquals,
  1649. Value: "ns3",
  1650. },
  1651. AllocationFilterCondition{
  1652. Field: FilterNamespace,
  1653. Op: FilterEquals,
  1654. Value: "ns2",
  1655. },
  1656. },
  1657. },
  1658. }},
  1659. expected: false,
  1660. },
  1661. {
  1662. left: AllocationFilterAnd{Filters: []AllocationFilter{
  1663. AllocationFilterNone{},
  1664. AllocationFilterCondition{
  1665. Field: FilterLabel,
  1666. Op: FilterStartsWith,
  1667. Key: "xyz",
  1668. Value: "kubecost",
  1669. },
  1670. AllocationFilterOr{
  1671. Filters: []AllocationFilter{
  1672. AllocationFilterCondition{
  1673. Field: FilterNamespace,
  1674. Op: FilterEquals,
  1675. Value: "ns1",
  1676. },
  1677. AllocationFilterCondition{
  1678. Field: FilterNamespace,
  1679. Op: FilterEquals,
  1680. Value: "ns2",
  1681. },
  1682. },
  1683. },
  1684. }},
  1685. right: AllocationFilterAnd{Filters: []AllocationFilter{
  1686. AllocationFilterCondition{
  1687. Field: FilterLabel,
  1688. Op: FilterStartsWith,
  1689. Key: "xyz",
  1690. Value: "kubecost",
  1691. },
  1692. AllocationFilterOr{
  1693. Filters: []AllocationFilter{
  1694. AllocationFilterCondition{
  1695. Field: FilterNamespace,
  1696. Op: FilterEquals,
  1697. Value: "ns1",
  1698. },
  1699. AllocationFilterCondition{
  1700. Field: FilterNamespace,
  1701. Op: FilterEquals,
  1702. Value: "ns2",
  1703. },
  1704. },
  1705. },
  1706. }},
  1707. expected: false,
  1708. },
  1709. }
  1710. for _, c := range cases {
  1711. t.Run(fmt.Sprintf("'%s' = '%s'", c.left, c.right), func(t *testing.T) {
  1712. if c.left.Equals(c.right) != c.expected {
  1713. t.Fatalf("Expected: %t", c.expected)
  1714. }
  1715. })
  1716. }
  1717. }