allocationprops_test.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. package kubecost
  2. import (
  3. "reflect"
  4. "testing"
  5. )
  6. func TestAllocationPropsIntersection(t *testing.T) {
  7. cases := map[string]struct {
  8. allocationProps1 *AllocationProperties
  9. allocationProps2 *AllocationProperties
  10. expected *AllocationProperties
  11. }{
  12. "intersection two allocation properties with empty labels/annotations": {
  13. allocationProps1: &AllocationProperties{
  14. Labels: map[string]string{},
  15. Annotations: map[string]string{},
  16. },
  17. allocationProps2: &AllocationProperties{
  18. Labels: map[string]string{},
  19. Annotations: map[string]string{},
  20. },
  21. expected: &AllocationProperties{
  22. Labels: nil,
  23. Annotations: nil,
  24. },
  25. },
  26. "nil intersection": {
  27. allocationProps1: nil,
  28. allocationProps2: nil,
  29. expected: nil,
  30. },
  31. "intersection, with labels/annotations, no aggregated metdata": {
  32. allocationProps1: &AllocationProperties{
  33. AggregatedMetadata: false,
  34. Node: "node1",
  35. Labels: map[string]string{"key1": "val1"},
  36. Annotations: map[string]string{"key2": "val2"},
  37. },
  38. allocationProps2: &AllocationProperties{
  39. AggregatedMetadata: false,
  40. Node: "node1",
  41. Labels: map[string]string{"key3": "val3"},
  42. Annotations: map[string]string{"key4": "val4"},
  43. },
  44. expected: &AllocationProperties{
  45. AggregatedMetadata: false,
  46. Node: "node1",
  47. Labels: nil,
  48. Annotations: nil,
  49. },
  50. },
  51. "intersection, with labels/annotations, with aggregated metdata": {
  52. allocationProps1: &AllocationProperties{
  53. AggregatedMetadata: false,
  54. ControllerKind: "controller1",
  55. Namespace: "ns1",
  56. Labels: map[string]string{"key1": "val1"},
  57. Annotations: map[string]string{"key2": "val2"},
  58. },
  59. allocationProps2: &AllocationProperties{
  60. AggregatedMetadata: true,
  61. ControllerKind: "controller2",
  62. Namespace: "ns1",
  63. Labels: map[string]string{"key1": "val1"},
  64. Annotations: map[string]string{"key2": "val2"},
  65. },
  66. expected: &AllocationProperties{
  67. AggregatedMetadata: true,
  68. Namespace: "ns1",
  69. ControllerKind: "",
  70. Labels: map[string]string{"key1": "val1"},
  71. Annotations: map[string]string{"key2": "val2"},
  72. },
  73. },
  74. "intersection, with labels/annotations, special case container": {
  75. allocationProps1: &AllocationProperties{
  76. AggregatedMetadata: false,
  77. Container: UnmountedSuffix,
  78. Namespace: "ns1",
  79. Labels: map[string]string{},
  80. Annotations: map[string]string{},
  81. },
  82. allocationProps2: &AllocationProperties{
  83. AggregatedMetadata: true,
  84. Container: "container3",
  85. Namespace: "ns1",
  86. Labels: map[string]string{"key1": "val1"},
  87. Annotations: map[string]string{"key2": "val2"},
  88. },
  89. expected: &AllocationProperties{
  90. AggregatedMetadata: true,
  91. Namespace: "ns1",
  92. ControllerKind: "",
  93. Labels: map[string]string{"key1": "val1"},
  94. Annotations: map[string]string{"key2": "val2"},
  95. },
  96. },
  97. "test services are nulled when intersecting": {
  98. allocationProps1: &AllocationProperties{
  99. AggregatedMetadata: false,
  100. Container: UnmountedSuffix,
  101. Namespace: "ns1",
  102. Services: []string{
  103. "cool",
  104. },
  105. Labels: map[string]string{},
  106. Annotations: map[string]string{},
  107. },
  108. allocationProps2: &AllocationProperties{
  109. AggregatedMetadata: true,
  110. Container: "container3",
  111. Namespace: "ns1",
  112. Labels: map[string]string{"key1": "val1"},
  113. Annotations: map[string]string{"key2": "val2"},
  114. },
  115. expected: &AllocationProperties{
  116. AggregatedMetadata: true,
  117. Namespace: "ns1",
  118. ControllerKind: "",
  119. Labels: map[string]string{"key1": "val1"},
  120. Annotations: map[string]string{"key2": "val2"},
  121. },
  122. },
  123. }
  124. for name, tc := range cases {
  125. t.Run(name, func(t *testing.T) {
  126. actual := tc.allocationProps1.Intersection(tc.allocationProps2)
  127. if !reflect.DeepEqual(actual, tc.expected) {
  128. t.Fatalf("test case %s: expected %+v; got %+v", name, tc.expected, actual)
  129. }
  130. })
  131. }
  132. }
  133. func TestGenerateKey(t *testing.T) {
  134. customOwnerLabelConfig := NewLabelConfig()
  135. customOwnerLabelConfig.OwnerLabel = "example_com_project"
  136. cases := map[string]struct {
  137. aggregate []string
  138. allocationProps *AllocationProperties
  139. labelConfig *LabelConfig
  140. expected string
  141. }{
  142. "aggregate by owner without owner labels": {
  143. aggregate: []string{"owner"},
  144. allocationProps: &AllocationProperties{
  145. Labels: map[string]string{"app": "cost-analyzer"},
  146. Annotations: map[string]string{"owner": "test owner 123"},
  147. },
  148. expected: "test owner 123",
  149. },
  150. "aggregate by owner without labels": {
  151. aggregate: []string{"owner"},
  152. allocationProps: &AllocationProperties{
  153. Annotations: map[string]string{"owner": "test owner 123"},
  154. },
  155. expected: "test owner 123",
  156. },
  157. "aggregate by owner with owner label and annotation": {
  158. aggregate: []string{"owner"},
  159. allocationProps: &AllocationProperties{
  160. Labels: map[string]string{"owner": "owner-label"},
  161. Annotations: map[string]string{"owner": "owner-annotation"},
  162. },
  163. expected: "owner-label",
  164. },
  165. "aggregate by environment with environment label and annotation": {
  166. aggregate: []string{"environment"},
  167. allocationProps: &AllocationProperties{
  168. Labels: map[string]string{"env": "environment-label"},
  169. Annotations: map[string]string{"env": "environment-annotation"},
  170. },
  171. expected: "environment-label",
  172. },
  173. "aggregate by department with department label and annotation": {
  174. aggregate: []string{"department"},
  175. allocationProps: &AllocationProperties{
  176. Labels: map[string]string{"department": "department-label"},
  177. Annotations: map[string]string{"department": "department-annotation"},
  178. },
  179. expected: "department-label",
  180. },
  181. "aggregate by team with team label and annotation": {
  182. aggregate: []string{"team"},
  183. allocationProps: &AllocationProperties{
  184. Labels: map[string]string{"team": "team-label"},
  185. Annotations: map[string]string{"team": "team-annotation"},
  186. },
  187. expected: "team-label",
  188. },
  189. "aggregate by product with product label and annotation": {
  190. aggregate: []string{"product"},
  191. allocationProps: &AllocationProperties{
  192. Labels: map[string]string{"app": "product-label"},
  193. Annotations: map[string]string{"app": "product-annotation"},
  194. },
  195. expected: "product-label",
  196. },
  197. "aggregate by product and owner with multiple labels and annotations": {
  198. aggregate: []string{"product", "owner"},
  199. allocationProps: &AllocationProperties{
  200. Labels: map[string]string{"app": "product-label", "owner": "owner-label", "team": "team-label"},
  201. Annotations: map[string]string{"app": "product-annotation", "owner": "owner-annotation", "team": "team-annotation"},
  202. },
  203. expected: "product-label/owner-label",
  204. },
  205. "user test": {
  206. aggregate: []string{"owner"},
  207. allocationProps: &AllocationProperties{
  208. Labels: map[string]string{"app_kubernetes_io_name": "x-mongo", "example_com_service_owner": "x", "component": "primary", "controller_revision_hash": "x-mongo-primary-x", "kubernetes_io_metadata_name": "app-microservices", "name": "app-microservices", "statefulset_kubernetes_io_pod_name": "x-mongo-primary-0"},
  209. Annotations: map[string]string{"example_com_project": "redacted"},
  210. },
  211. labelConfig: customOwnerLabelConfig,
  212. expected: "redacted",
  213. },
  214. }
  215. for name, tc := range cases {
  216. t.Run(name, func(t *testing.T) {
  217. lc := NewLabelConfig()
  218. if tc.labelConfig != nil {
  219. lc = tc.labelConfig
  220. }
  221. result := tc.allocationProps.GenerateKey(tc.aggregate, lc)
  222. if !reflect.DeepEqual(result, tc.expected) {
  223. t.Fatalf("expected %+v; got %+v", tc.expected, result)
  224. }
  225. })
  226. }
  227. }