allocationprops_test.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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. }
  98. for name, tc := range cases {
  99. t.Run(name, func(t *testing.T) {
  100. actual := tc.allocationProps1.Intersection(tc.allocationProps2)
  101. if !reflect.DeepEqual(actual, tc.expected) {
  102. t.Fatalf("test case %s: expected %+v; got %+v", name, tc.expected, actual)
  103. }
  104. })
  105. }
  106. }
  107. func TestGenerateKey(t *testing.T) {
  108. customOwnerLabelConfig := NewLabelConfig()
  109. customOwnerLabelConfig.OwnerLabel = "example_com_project"
  110. cases := map[string]struct {
  111. aggregate []string
  112. allocationProps *AllocationProperties
  113. labelConfig *LabelConfig
  114. expected string
  115. }{
  116. "aggregate by owner without owner labels": {
  117. aggregate: []string{"owner"},
  118. allocationProps: &AllocationProperties{
  119. Labels: map[string]string{"app": "cost-analyzer"},
  120. Annotations: map[string]string{"owner": "test owner 123"},
  121. },
  122. expected: "test owner 123",
  123. },
  124. "aggregate by owner without labels": {
  125. aggregate: []string{"owner"},
  126. allocationProps: &AllocationProperties{
  127. Annotations: map[string]string{"owner": "test owner 123"},
  128. },
  129. expected: "test owner 123",
  130. },
  131. "aggregate by owner with owner label and annotation": {
  132. aggregate: []string{"owner"},
  133. allocationProps: &AllocationProperties{
  134. Labels: map[string]string{"owner": "owner-label"},
  135. Annotations: map[string]string{"owner": "owner-annotation"},
  136. },
  137. expected: "owner-label",
  138. },
  139. "aggregate by environment with environment label and annotation": {
  140. aggregate: []string{"environment"},
  141. allocationProps: &AllocationProperties{
  142. Labels: map[string]string{"env": "environment-label"},
  143. Annotations: map[string]string{"env": "environment-annotation"},
  144. },
  145. expected: "environment-label",
  146. },
  147. "aggregate by department with department label and annotation": {
  148. aggregate: []string{"department"},
  149. allocationProps: &AllocationProperties{
  150. Labels: map[string]string{"department": "department-label"},
  151. Annotations: map[string]string{"department": "department-annotation"},
  152. },
  153. expected: "department-label",
  154. },
  155. "aggregate by team with team label and annotation": {
  156. aggregate: []string{"team"},
  157. allocationProps: &AllocationProperties{
  158. Labels: map[string]string{"team": "team-label"},
  159. Annotations: map[string]string{"team": "team-annotation"},
  160. },
  161. expected: "team-label",
  162. },
  163. "aggregate by product with product label and annotation": {
  164. aggregate: []string{"product"},
  165. allocationProps: &AllocationProperties{
  166. Labels: map[string]string{"app": "product-label"},
  167. Annotations: map[string]string{"app": "product-annotation"},
  168. },
  169. expected: "product-label",
  170. },
  171. "aggregate by product and owner with multiple labels and annotations": {
  172. aggregate: []string{"product", "owner"},
  173. allocationProps: &AllocationProperties{
  174. Labels: map[string]string{"app": "product-label", "owner": "owner-label", "team": "team-label"},
  175. Annotations: map[string]string{"app": "product-annotation", "owner": "owner-annotation", "team": "team-annotation"},
  176. },
  177. expected: "product-label/owner-label",
  178. },
  179. "user test": {
  180. aggregate: []string{"owner"},
  181. allocationProps: &AllocationProperties{
  182. 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"},
  183. Annotations: map[string]string{"example_com_project": "redacted"},
  184. },
  185. labelConfig: customOwnerLabelConfig,
  186. expected: "redacted",
  187. },
  188. }
  189. for name, tc := range cases {
  190. t.Run(name, func(t *testing.T) {
  191. lc := NewLabelConfig()
  192. if tc.labelConfig != nil {
  193. lc = tc.labelConfig
  194. }
  195. result := tc.allocationProps.GenerateKey(tc.aggregate, lc)
  196. if !reflect.DeepEqual(result, tc.expected) {
  197. t.Fatalf("expected %+v; got %+v", tc.expected, result)
  198. }
  199. })
  200. }
  201. }