allocationfilter_test.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  1. package kubecost
  2. import (
  3. "reflect"
  4. "testing"
  5. )
  6. func Test_AllocationFilterCondition_Matches(t *testing.T) {
  7. cases := []struct {
  8. name string
  9. a *Allocation
  10. filter AllocationFilter
  11. expected bool
  12. }{
  13. {
  14. name: "ClusterID Equals -> true",
  15. a: &Allocation{
  16. Properties: &AllocationProperties{
  17. Cluster: "cluster-one",
  18. },
  19. },
  20. filter: AllocationFilterCondition{
  21. Field: FilterClusterID,
  22. Op: FilterEquals,
  23. Value: "cluster-one",
  24. },
  25. expected: true,
  26. },
  27. {
  28. name: "ClusterID StartsWith -> true",
  29. a: &Allocation{
  30. Properties: &AllocationProperties{
  31. Cluster: "cluster-one",
  32. },
  33. },
  34. filter: AllocationFilterCondition{
  35. Field: FilterClusterID,
  36. Op: FilterStartsWith,
  37. Value: "cluster",
  38. },
  39. expected: true,
  40. },
  41. {
  42. name: "ClusterID StartsWith -> false",
  43. a: &Allocation{
  44. Properties: &AllocationProperties{
  45. Cluster: "k8s-one",
  46. },
  47. },
  48. filter: AllocationFilterCondition{
  49. Field: FilterClusterID,
  50. Op: FilterStartsWith,
  51. Value: "cluster",
  52. },
  53. expected: false,
  54. },
  55. {
  56. name: "ClusterID empty StartsWith '' -> true",
  57. a: &Allocation{
  58. Properties: &AllocationProperties{
  59. Cluster: "",
  60. },
  61. },
  62. filter: AllocationFilterCondition{
  63. Field: FilterClusterID,
  64. Op: FilterStartsWith,
  65. Value: "",
  66. },
  67. expected: true,
  68. },
  69. {
  70. name: "ClusterID nonempty StartsWith '' -> true",
  71. a: &Allocation{
  72. Properties: &AllocationProperties{
  73. Cluster: "abc",
  74. },
  75. },
  76. filter: AllocationFilterCondition{
  77. Field: FilterClusterID,
  78. Op: FilterStartsWith,
  79. Value: "",
  80. },
  81. expected: true,
  82. },
  83. {
  84. name: "Node Equals -> true",
  85. a: &Allocation{
  86. Properties: &AllocationProperties{
  87. Node: "node123",
  88. },
  89. },
  90. filter: AllocationFilterCondition{
  91. Field: FilterNode,
  92. Op: FilterEquals,
  93. Value: "node123",
  94. },
  95. expected: true,
  96. },
  97. {
  98. name: "Namespace NotEquals -> false",
  99. a: &Allocation{
  100. Properties: &AllocationProperties{
  101. Namespace: "kube-system",
  102. },
  103. },
  104. filter: AllocationFilterCondition{
  105. Field: FilterNamespace,
  106. Op: FilterNotEquals,
  107. Value: "kube-system",
  108. },
  109. expected: false,
  110. },
  111. {
  112. name: "Namespace NotEquals Unallocated -> true",
  113. a: &Allocation{
  114. Properties: &AllocationProperties{
  115. Namespace: "kube-system",
  116. },
  117. },
  118. filter: AllocationFilterCondition{
  119. Field: FilterNamespace,
  120. Op: FilterNotEquals,
  121. Value: UnallocatedSuffix,
  122. },
  123. expected: true,
  124. },
  125. {
  126. name: "Namespace NotEquals Unallocated -> false",
  127. a: &Allocation{
  128. Properties: &AllocationProperties{
  129. Namespace: "",
  130. },
  131. },
  132. filter: AllocationFilterCondition{
  133. Field: FilterNamespace,
  134. Op: FilterNotEquals,
  135. Value: UnallocatedSuffix,
  136. },
  137. expected: false,
  138. },
  139. {
  140. name: "Namespace Equals Unallocated -> true",
  141. a: &Allocation{
  142. Properties: &AllocationProperties{
  143. Namespace: "",
  144. },
  145. },
  146. filter: AllocationFilterCondition{
  147. Field: FilterNamespace,
  148. Op: FilterEquals,
  149. Value: UnallocatedSuffix,
  150. },
  151. expected: true,
  152. },
  153. {
  154. name: "ControllerKind Equals -> true",
  155. a: &Allocation{
  156. Properties: &AllocationProperties{
  157. ControllerKind: "deployment", // We generally store controller kinds as all lowercase
  158. },
  159. },
  160. filter: AllocationFilterCondition{
  161. Field: FilterControllerKind,
  162. Op: FilterEquals,
  163. Value: "deployment",
  164. },
  165. expected: true,
  166. },
  167. {
  168. name: "ControllerName Equals -> true",
  169. a: &Allocation{
  170. Properties: &AllocationProperties{
  171. Controller: "kc-cost-analyzer",
  172. },
  173. },
  174. filter: AllocationFilterCondition{
  175. Field: FilterControllerName,
  176. Op: FilterEquals,
  177. Value: "kc-cost-analyzer",
  178. },
  179. expected: true,
  180. },
  181. {
  182. name: "Pod (with UID) Equals -> true",
  183. a: &Allocation{
  184. Properties: &AllocationProperties{
  185. Pod: "pod-123 UID-ABC",
  186. },
  187. },
  188. filter: AllocationFilterCondition{
  189. Field: FilterPod,
  190. Op: FilterEquals,
  191. Value: "pod-123 UID-ABC",
  192. },
  193. expected: true,
  194. },
  195. {
  196. name: "Container Equals -> true",
  197. a: &Allocation{
  198. Properties: &AllocationProperties{
  199. Container: "cost-model",
  200. },
  201. },
  202. filter: AllocationFilterCondition{
  203. Field: FilterContainer,
  204. Op: FilterEquals,
  205. Value: "cost-model",
  206. },
  207. expected: true,
  208. },
  209. {
  210. name: `label[app]="foo" -> true`,
  211. a: &Allocation{
  212. Properties: &AllocationProperties{
  213. Labels: map[string]string{
  214. "app": "foo",
  215. },
  216. },
  217. },
  218. filter: AllocationFilterCondition{
  219. Field: FilterLabel,
  220. Op: FilterEquals,
  221. Key: "app",
  222. Value: "foo",
  223. },
  224. expected: true,
  225. },
  226. {
  227. name: `label[app]="foo" -> different value -> false`,
  228. a: &Allocation{
  229. Properties: &AllocationProperties{
  230. Labels: map[string]string{
  231. "app": "bar",
  232. },
  233. },
  234. },
  235. filter: AllocationFilterCondition{
  236. Field: FilterLabel,
  237. Op: FilterEquals,
  238. Key: "app",
  239. Value: "foo",
  240. },
  241. expected: false,
  242. },
  243. {
  244. name: `label[app]="foo" -> label missing -> false`,
  245. a: &Allocation{
  246. Properties: &AllocationProperties{
  247. Labels: map[string]string{
  248. "someotherlabel": "someothervalue",
  249. },
  250. },
  251. },
  252. filter: AllocationFilterCondition{
  253. Field: FilterLabel,
  254. Op: FilterEquals,
  255. Key: "app",
  256. Value: "foo",
  257. },
  258. expected: false,
  259. },
  260. {
  261. name: `label[app]=Unallocated -> label missing -> true`,
  262. a: &Allocation{
  263. Properties: &AllocationProperties{
  264. Labels: map[string]string{
  265. "someotherlabel": "someothervalue",
  266. },
  267. },
  268. },
  269. filter: AllocationFilterCondition{
  270. Field: FilterLabel,
  271. Op: FilterEquals,
  272. Key: "app",
  273. Value: UnallocatedSuffix,
  274. },
  275. expected: true,
  276. },
  277. {
  278. name: `label[app]=Unallocated -> label present -> false`,
  279. a: &Allocation{
  280. Properties: &AllocationProperties{
  281. Labels: map[string]string{
  282. "app": "test",
  283. },
  284. },
  285. },
  286. filter: AllocationFilterCondition{
  287. Field: FilterLabel,
  288. Op: FilterEquals,
  289. Key: "app",
  290. Value: UnallocatedSuffix,
  291. },
  292. expected: false,
  293. },
  294. {
  295. name: `label[app]!=Unallocated -> label missing -> false`,
  296. a: &Allocation{
  297. Properties: &AllocationProperties{
  298. Labels: map[string]string{
  299. "someotherlabel": "someothervalue",
  300. },
  301. },
  302. },
  303. filter: AllocationFilterCondition{
  304. Field: FilterLabel,
  305. Op: FilterNotEquals,
  306. Key: "app",
  307. Value: UnallocatedSuffix,
  308. },
  309. expected: false,
  310. },
  311. {
  312. name: `label[app]!=Unallocated -> label present -> true`,
  313. a: &Allocation{
  314. Properties: &AllocationProperties{
  315. Labels: map[string]string{
  316. "app": "test",
  317. },
  318. },
  319. },
  320. filter: AllocationFilterCondition{
  321. Field: FilterLabel,
  322. Op: FilterNotEquals,
  323. Key: "app",
  324. Value: UnallocatedSuffix,
  325. },
  326. expected: true,
  327. },
  328. {
  329. name: `label[app]!="foo" -> label missing -> true`,
  330. a: &Allocation{
  331. Properties: &AllocationProperties{
  332. Labels: map[string]string{
  333. "someotherlabel": "someothervalue",
  334. },
  335. },
  336. },
  337. filter: AllocationFilterCondition{
  338. Field: FilterLabel,
  339. Op: FilterNotEquals,
  340. Key: "app",
  341. Value: "foo",
  342. },
  343. expected: true,
  344. },
  345. {
  346. name: `annotation[prom_modified_name]="testing123" -> true`,
  347. a: &Allocation{
  348. Properties: &AllocationProperties{
  349. Annotations: map[string]string{
  350. "prom_modified_name": "testing123",
  351. },
  352. },
  353. },
  354. filter: AllocationFilterCondition{
  355. Field: FilterAnnotation,
  356. Op: FilterEquals,
  357. Key: "prom_modified_name",
  358. Value: "testing123",
  359. },
  360. expected: true,
  361. },
  362. {
  363. name: `annotation[app]="foo" -> different value -> false`,
  364. a: &Allocation{
  365. Properties: &AllocationProperties{
  366. Annotations: map[string]string{
  367. "app": "bar",
  368. },
  369. },
  370. },
  371. filter: AllocationFilterCondition{
  372. Field: FilterAnnotation,
  373. Op: FilterEquals,
  374. Key: "app",
  375. Value: "foo",
  376. },
  377. expected: false,
  378. },
  379. {
  380. name: `annotation[app]="foo" -> annotation missing -> false`,
  381. a: &Allocation{
  382. Properties: &AllocationProperties{
  383. Annotations: map[string]string{
  384. "someotherannotation": "someothervalue",
  385. },
  386. },
  387. },
  388. filter: AllocationFilterCondition{
  389. Field: FilterAnnotation,
  390. Op: FilterEquals,
  391. Key: "app",
  392. Value: "foo",
  393. },
  394. expected: false,
  395. },
  396. {
  397. name: `annotation[app]!="foo" -> annotation missing -> true`,
  398. a: &Allocation{
  399. Properties: &AllocationProperties{
  400. Annotations: map[string]string{
  401. "someotherannotation": "someothervalue",
  402. },
  403. },
  404. },
  405. filter: AllocationFilterCondition{
  406. Field: FilterAnnotation,
  407. Op: FilterNotEquals,
  408. Key: "app",
  409. Value: "foo",
  410. },
  411. expected: true,
  412. },
  413. {
  414. name: `namespace unallocated -> true`,
  415. a: &Allocation{
  416. Properties: &AllocationProperties{
  417. Namespace: "",
  418. },
  419. },
  420. filter: AllocationFilterCondition{
  421. Field: FilterNamespace,
  422. Op: FilterEquals,
  423. Value: UnallocatedSuffix,
  424. },
  425. expected: true,
  426. },
  427. {
  428. name: `services contains -> true`,
  429. a: &Allocation{
  430. Properties: &AllocationProperties{
  431. Services: []string{"serv1", "serv2"},
  432. },
  433. },
  434. filter: AllocationFilterCondition{
  435. Field: FilterServices,
  436. Op: FilterContains,
  437. Value: "serv2",
  438. },
  439. expected: true,
  440. },
  441. {
  442. name: `services contains -> false`,
  443. a: &Allocation{
  444. Properties: &AllocationProperties{
  445. Services: []string{"serv1", "serv2"},
  446. },
  447. },
  448. filter: AllocationFilterCondition{
  449. Field: FilterServices,
  450. Op: FilterContains,
  451. Value: "serv3",
  452. },
  453. expected: false,
  454. },
  455. {
  456. name: `services notcontains -> true`,
  457. a: &Allocation{
  458. Properties: &AllocationProperties{
  459. Services: []string{"serv1", "serv2"},
  460. },
  461. },
  462. filter: AllocationFilterCondition{
  463. Field: FilterServices,
  464. Op: FilterNotContains,
  465. Value: "serv3",
  466. },
  467. expected: true,
  468. },
  469. {
  470. name: `services notcontains -> false`,
  471. a: &Allocation{
  472. Properties: &AllocationProperties{
  473. Services: []string{"serv1", "serv2"},
  474. },
  475. },
  476. filter: AllocationFilterCondition{
  477. Field: FilterServices,
  478. Op: FilterNotContains,
  479. Value: "serv2",
  480. },
  481. expected: false,
  482. },
  483. {
  484. name: `services notcontains unallocated -> true`,
  485. a: &Allocation{
  486. Properties: &AllocationProperties{
  487. Services: []string{"serv1", "serv2"},
  488. },
  489. },
  490. filter: AllocationFilterCondition{
  491. Field: FilterServices,
  492. Op: FilterNotContains,
  493. Value: UnallocatedSuffix,
  494. },
  495. expected: true,
  496. },
  497. {
  498. name: `services notcontains unallocated -> false`,
  499. a: &Allocation{
  500. Properties: &AllocationProperties{
  501. Services: []string{},
  502. },
  503. },
  504. filter: AllocationFilterCondition{
  505. Field: FilterServices,
  506. Op: FilterNotContains,
  507. Value: UnallocatedSuffix,
  508. },
  509. expected: false,
  510. },
  511. {
  512. name: `services containsprefix -> true`,
  513. a: &Allocation{
  514. Properties: &AllocationProperties{
  515. Services: []string{"serv1", "serv2"},
  516. },
  517. },
  518. filter: AllocationFilterCondition{
  519. Field: FilterServices,
  520. Op: FilterContainsPrefix,
  521. Value: "serv",
  522. },
  523. expected: true,
  524. },
  525. {
  526. name: `services containsprefix -> false`,
  527. a: &Allocation{
  528. Properties: &AllocationProperties{
  529. Services: []string{"foo", "bar"},
  530. },
  531. },
  532. filter: AllocationFilterCondition{
  533. Field: FilterServices,
  534. Op: FilterContainsPrefix,
  535. Value: "serv",
  536. },
  537. expected: false,
  538. },
  539. {
  540. name: `services contains unallocated -> false`,
  541. a: &Allocation{
  542. Properties: &AllocationProperties{
  543. Services: []string{"serv1", "serv2"},
  544. },
  545. },
  546. filter: AllocationFilterCondition{
  547. Field: FilterServices,
  548. Op: FilterContains,
  549. Value: UnallocatedSuffix,
  550. },
  551. expected: false,
  552. },
  553. {
  554. name: `services contains unallocated -> true`,
  555. a: &Allocation{
  556. Properties: &AllocationProperties{
  557. Services: []string{},
  558. },
  559. },
  560. filter: AllocationFilterCondition{
  561. Field: FilterServices,
  562. Op: FilterContains,
  563. Value: UnallocatedSuffix,
  564. },
  565. expected: true,
  566. },
  567. }
  568. for _, c := range cases {
  569. result := c.filter.Matches(c.a)
  570. if result != c.expected {
  571. t.Errorf("%s: expected %t, got %t", c.name, c.expected, result)
  572. }
  573. }
  574. }
  575. func Test_AllocationFilterAnd_Matches(t *testing.T) {
  576. cases := []struct {
  577. name string
  578. a *Allocation
  579. filter AllocationFilter
  580. expected bool
  581. }{
  582. {
  583. name: `label[app]="foo" and namespace="kubecost" -> both true`,
  584. a: &Allocation{
  585. Properties: &AllocationProperties{
  586. Namespace: "kubecost",
  587. Labels: map[string]string{
  588. "app": "foo",
  589. },
  590. },
  591. },
  592. filter: AllocationFilterAnd{[]AllocationFilter{
  593. AllocationFilterCondition{
  594. Field: FilterLabel,
  595. Op: FilterEquals,
  596. Key: "app",
  597. Value: "foo",
  598. },
  599. AllocationFilterCondition{
  600. Field: FilterNamespace,
  601. Op: FilterEquals,
  602. Value: "kubecost",
  603. },
  604. }},
  605. expected: true,
  606. },
  607. {
  608. name: `label[app]="foo" and namespace="kubecost" -> first true`,
  609. a: &Allocation{
  610. Properties: &AllocationProperties{
  611. Namespace: "kube-system",
  612. Labels: map[string]string{
  613. "app": "foo",
  614. },
  615. },
  616. },
  617. filter: AllocationFilterAnd{[]AllocationFilter{
  618. AllocationFilterCondition{
  619. Field: FilterLabel,
  620. Op: FilterEquals,
  621. Key: "app",
  622. Value: "foo",
  623. },
  624. AllocationFilterCondition{
  625. Field: FilterNamespace,
  626. Op: FilterEquals,
  627. Value: "kubecost",
  628. },
  629. }},
  630. expected: false,
  631. },
  632. {
  633. name: `label[app]="foo" and namespace="kubecost" -> second true`,
  634. a: &Allocation{
  635. Properties: &AllocationProperties{
  636. Namespace: "kubecost",
  637. Labels: map[string]string{
  638. "app": "bar",
  639. },
  640. },
  641. },
  642. filter: AllocationFilterAnd{[]AllocationFilter{
  643. AllocationFilterCondition{
  644. Field: FilterLabel,
  645. Op: FilterEquals,
  646. Key: "app",
  647. Value: "foo",
  648. },
  649. AllocationFilterCondition{
  650. Field: FilterNamespace,
  651. Op: FilterEquals,
  652. Value: "kubecost",
  653. },
  654. }},
  655. expected: false,
  656. },
  657. {
  658. name: `label[app]="foo" and namespace="kubecost" -> both false`,
  659. a: &Allocation{
  660. Properties: &AllocationProperties{
  661. Namespace: "kube-system",
  662. Labels: map[string]string{
  663. "app": "bar",
  664. },
  665. },
  666. },
  667. filter: AllocationFilterAnd{[]AllocationFilter{
  668. AllocationFilterCondition{
  669. Field: FilterLabel,
  670. Op: FilterEquals,
  671. Key: "app",
  672. Value: "foo",
  673. },
  674. AllocationFilterCondition{
  675. Field: FilterNamespace,
  676. Op: FilterEquals,
  677. Value: "kubecost",
  678. },
  679. }},
  680. expected: false,
  681. },
  682. }
  683. for _, c := range cases {
  684. result := c.filter.Matches(c.a)
  685. if result != c.expected {
  686. t.Errorf("%s: expected %t, got %t", c.name, c.expected, result)
  687. }
  688. }
  689. }
  690. func Test_AllocationFilterOr_Matches(t *testing.T) {
  691. cases := []struct {
  692. name string
  693. a *Allocation
  694. filter AllocationFilter
  695. expected bool
  696. }{
  697. {
  698. name: `label[app]="foo" or namespace="kubecost" -> both true`,
  699. a: &Allocation{
  700. Properties: &AllocationProperties{
  701. Namespace: "kubecost",
  702. Labels: map[string]string{
  703. "app": "foo",
  704. },
  705. },
  706. },
  707. filter: AllocationFilterOr{[]AllocationFilter{
  708. AllocationFilterCondition{
  709. Field: FilterLabel,
  710. Op: FilterEquals,
  711. Key: "app",
  712. Value: "foo",
  713. },
  714. AllocationFilterCondition{
  715. Field: FilterNamespace,
  716. Op: FilterEquals,
  717. Value: "kubecost",
  718. },
  719. }},
  720. expected: true,
  721. },
  722. {
  723. name: `label[app]="foo" or namespace="kubecost" -> first true`,
  724. a: &Allocation{
  725. Properties: &AllocationProperties{
  726. Namespace: "kube-system",
  727. Labels: map[string]string{
  728. "app": "foo",
  729. },
  730. },
  731. },
  732. filter: AllocationFilterOr{[]AllocationFilter{
  733. AllocationFilterCondition{
  734. Field: FilterLabel,
  735. Op: FilterEquals,
  736. Key: "app",
  737. Value: "foo",
  738. },
  739. AllocationFilterCondition{
  740. Field: FilterNamespace,
  741. Op: FilterEquals,
  742. Value: "kubecost",
  743. },
  744. }},
  745. expected: true,
  746. },
  747. {
  748. name: `label[app]="foo" or namespace="kubecost" -> second true`,
  749. a: &Allocation{
  750. Properties: &AllocationProperties{
  751. Namespace: "kubecost",
  752. Labels: map[string]string{
  753. "app": "bar",
  754. },
  755. },
  756. },
  757. filter: AllocationFilterOr{[]AllocationFilter{
  758. AllocationFilterCondition{
  759. Field: FilterLabel,
  760. Op: FilterEquals,
  761. Key: "app",
  762. Value: "foo",
  763. },
  764. AllocationFilterCondition{
  765. Field: FilterNamespace,
  766. Op: FilterEquals,
  767. Value: "kubecost",
  768. },
  769. }},
  770. expected: true,
  771. },
  772. {
  773. name: `label[app]="foo" or namespace="kubecost" -> both false`,
  774. a: &Allocation{
  775. Properties: &AllocationProperties{
  776. Namespace: "kube-system",
  777. Labels: map[string]string{
  778. "app": "bar",
  779. },
  780. },
  781. },
  782. filter: AllocationFilterOr{[]AllocationFilter{
  783. AllocationFilterCondition{
  784. Field: FilterLabel,
  785. Op: FilterEquals,
  786. Key: "app",
  787. Value: "foo",
  788. },
  789. AllocationFilterCondition{
  790. Field: FilterNamespace,
  791. Op: FilterEquals,
  792. Value: "kubecost",
  793. },
  794. }},
  795. expected: false,
  796. },
  797. }
  798. for _, c := range cases {
  799. result := c.filter.Matches(c.a)
  800. if result != c.expected {
  801. t.Errorf("%s: expected %t, got %t", c.name, c.expected, result)
  802. }
  803. }
  804. }
  805. func Test_AllocationFilter_Flattened(t *testing.T) {
  806. cases := []struct {
  807. name string
  808. input AllocationFilter
  809. expected AllocationFilter
  810. }{
  811. {
  812. name: "AllocationFilterCondition",
  813. input: AllocationFilterCondition{
  814. Field: FilterNamespace,
  815. Op: FilterEquals,
  816. },
  817. expected: AllocationFilterCondition{
  818. Field: FilterNamespace,
  819. Op: FilterEquals,
  820. },
  821. },
  822. {
  823. name: "empty AllocationFilterAnd (nil)",
  824. input: AllocationFilterAnd{},
  825. expected: nil,
  826. },
  827. {
  828. name: "empty AllocationFilterAnd (len 0)",
  829. input: AllocationFilterAnd{Filters: []AllocationFilter{}},
  830. expected: nil,
  831. },
  832. {
  833. name: "empty AllocationFilterOr (nil)",
  834. input: AllocationFilterOr{},
  835. expected: nil,
  836. },
  837. {
  838. name: "empty AllocationFilterOr (len 0)",
  839. input: AllocationFilterOr{Filters: []AllocationFilter{}},
  840. expected: nil,
  841. },
  842. {
  843. name: "single-element AllocationFilterAnd",
  844. input: AllocationFilterAnd{Filters: []AllocationFilter{
  845. AllocationFilterCondition{
  846. Field: FilterNamespace,
  847. Op: FilterEquals,
  848. },
  849. }},
  850. expected: AllocationFilterCondition{
  851. Field: FilterNamespace,
  852. Op: FilterEquals,
  853. },
  854. },
  855. {
  856. name: "single-element AllocationFilterOr",
  857. input: AllocationFilterOr{Filters: []AllocationFilter{
  858. AllocationFilterCondition{
  859. Field: FilterNamespace,
  860. Op: FilterEquals,
  861. },
  862. }},
  863. expected: AllocationFilterCondition{
  864. Field: FilterNamespace,
  865. Op: FilterEquals,
  866. },
  867. },
  868. {
  869. name: "multi-element AllocationFilterAnd",
  870. input: AllocationFilterAnd{Filters: []AllocationFilter{
  871. AllocationFilterCondition{
  872. Field: FilterNamespace,
  873. Op: FilterEquals,
  874. },
  875. AllocationFilterCondition{
  876. Field: FilterClusterID,
  877. Op: FilterNotEquals,
  878. },
  879. AllocationFilterCondition{
  880. Field: FilterServices,
  881. Op: FilterContains,
  882. },
  883. }},
  884. expected: AllocationFilterAnd{Filters: []AllocationFilter{
  885. AllocationFilterCondition{
  886. Field: FilterNamespace,
  887. Op: FilterEquals,
  888. },
  889. AllocationFilterCondition{
  890. Field: FilterClusterID,
  891. Op: FilterNotEquals,
  892. },
  893. AllocationFilterCondition{
  894. Field: FilterServices,
  895. Op: FilterContains,
  896. },
  897. }},
  898. },
  899. {
  900. name: "multi-element AllocationFilterOr",
  901. input: AllocationFilterOr{Filters: []AllocationFilter{
  902. AllocationFilterCondition{
  903. Field: FilterNamespace,
  904. Op: FilterEquals,
  905. },
  906. AllocationFilterCondition{
  907. Field: FilterClusterID,
  908. Op: FilterNotEquals,
  909. },
  910. AllocationFilterCondition{
  911. Field: FilterServices,
  912. Op: FilterContains,
  913. },
  914. }},
  915. expected: AllocationFilterOr{Filters: []AllocationFilter{
  916. AllocationFilterCondition{
  917. Field: FilterNamespace,
  918. Op: FilterEquals,
  919. },
  920. AllocationFilterCondition{
  921. Field: FilterClusterID,
  922. Op: FilterNotEquals,
  923. },
  924. AllocationFilterCondition{
  925. Field: FilterServices,
  926. Op: FilterContains,
  927. },
  928. }},
  929. },
  930. }
  931. for _, c := range cases {
  932. t.Run(c.name, func(t *testing.T) {
  933. result := c.input.Flattened()
  934. if !reflect.DeepEqual(result, c.expected) {
  935. t.Errorf("Expected: '%s'. Got '%s'.", c.expected, result)
  936. }
  937. })
  938. }
  939. }