summaryallocation_test.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. package kubecost
  2. import (
  3. "testing"
  4. "time"
  5. "github.com/opencost/opencost/pkg/util"
  6. )
  7. func TestSummaryAllocation_Add(t *testing.T) {
  8. window, _ := ParseWindowUTC("yesterday")
  9. var sa1, sa2, osa1, osa2, nilsa *SummaryAllocation
  10. var err error
  11. sa1Start := *window.Start()
  12. sa1End := *window.End()
  13. sa1 = &SummaryAllocation{
  14. Name: "cluster1/namespace1/pod1/container1",
  15. Properties: &AllocationProperties{
  16. Cluster: "cluster1",
  17. Namespace: "namespace1",
  18. Pod: "pod1",
  19. Container: "container1",
  20. },
  21. Start: sa1Start,
  22. End: sa1End,
  23. CPUCoreRequestAverage: 0.5,
  24. CPUCoreUsageAverage: 0.1,
  25. CPUCost: 0.2,
  26. GPUCost: 1.0,
  27. NetworkCost: 0.1,
  28. LoadBalancerCost: 0.6,
  29. PVCost: 0.005,
  30. RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
  31. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  32. RAMCost: 0.05,
  33. SharedCost: 1.0,
  34. ExternalCost: 1.0,
  35. }
  36. osa1 = sa1.Clone()
  37. // sa2 is just as expensive, with twice as much usage and request, and half
  38. // the time compared to sa1
  39. sa2Start := *window.Start()
  40. sa2Start = sa2Start.Add(6 * time.Hour)
  41. sa2End := *window.End()
  42. sa2End = sa2End.Add(-6 * time.Hour)
  43. sa2 = &SummaryAllocation{
  44. Name: "cluster1/namespace1/pod2/container2",
  45. Properties: &AllocationProperties{
  46. Cluster: "cluster1",
  47. Namespace: "namespace1",
  48. Pod: "pod2",
  49. Container: "container2",
  50. },
  51. Start: sa2Start,
  52. End: sa2End,
  53. CPUCoreRequestAverage: sa1.CPUCoreRequestAverage * 2.0,
  54. CPUCoreUsageAverage: sa1.CPUCoreUsageAverage * 2.0,
  55. CPUCost: sa1.CPUCost,
  56. GPUCost: sa1.GPUCost,
  57. NetworkCost: sa1.NetworkCost,
  58. LoadBalancerCost: sa1.LoadBalancerCost,
  59. PVCost: sa1.PVCost,
  60. RAMBytesRequestAverage: sa1.RAMBytesRequestAverage * 2.0,
  61. RAMBytesUsageAverage: sa1.RAMBytesUsageAverage * 2.0,
  62. RAMCost: sa1.RAMCost,
  63. SharedCost: sa1.SharedCost,
  64. ExternalCost: sa1.ExternalCost,
  65. }
  66. osa2 = sa2.Clone()
  67. // add nil to nil, expect and error
  68. t.Run("nil.Add(nil)", func(t *testing.T) {
  69. err = nilsa.Add(nilsa)
  70. if err == nil {
  71. t.Fatalf("expected error: cannot add nil SummaryAllocations")
  72. }
  73. })
  74. // reset
  75. sa1 = osa1.Clone()
  76. sa2 = osa2.Clone()
  77. // add sa1 to nil, expect and error
  78. t.Run("nil.Add(sa1)", func(t *testing.T) {
  79. err = nilsa.Add(sa1)
  80. if err == nil {
  81. t.Fatalf("expected error: cannot add nil SummaryAllocations")
  82. }
  83. })
  84. // reset
  85. sa1 = osa1.Clone()
  86. sa2 = osa2.Clone()
  87. // add nil to sa1, expect and error
  88. t.Run("sa1.Add(nil)", func(t *testing.T) {
  89. err = sa1.Add(nilsa)
  90. if err == nil {
  91. t.Fatalf("expected error: cannot add nil SummaryAllocations")
  92. }
  93. })
  94. // reset
  95. sa1 = osa1.Clone()
  96. sa2 = osa2.Clone()
  97. // add sa1 to sa2 and expect same averages, but double costs
  98. t.Run("sa2.Add(sa1)", func(t *testing.T) {
  99. err = sa2.Add(sa1)
  100. if err != nil {
  101. t.Fatalf("unexpected error: %s", err)
  102. }
  103. if sa2.Properties != nil {
  104. t.Fatalf("expected properties to be nil; actual: %s", sa1.Properties)
  105. }
  106. if !util.IsApproximately(sa2.CPUCoreRequestAverage, (0.5*osa2.CPUCoreRequestAverage)+osa1.CPUCoreRequestAverage) {
  107. t.Fatalf("incorrect CPUCoreRequestAverage: expected %.5f; actual %.5f", (0.5*osa2.CPUCoreRequestAverage)+osa1.CPUCoreRequestAverage, sa2.CPUCoreRequestAverage)
  108. }
  109. if !util.IsApproximately(sa2.CPUCoreUsageAverage, (0.5*osa2.CPUCoreUsageAverage)+osa1.CPUCoreUsageAverage) {
  110. t.Fatalf("incorrect CPUCoreUsageAverage: expected %.5f; actual %.5f", (0.5*osa2.CPUCoreUsageAverage)+osa1.CPUCoreRequestAverage, sa2.CPUCoreUsageAverage)
  111. }
  112. if !util.IsApproximately(sa2.RAMBytesRequestAverage, (0.5*osa2.RAMBytesRequestAverage)+osa1.RAMBytesRequestAverage) {
  113. t.Fatalf("incorrect RAMBytesRequestAverage: expected %.5f; actual %.5f", (0.5*osa2.RAMBytesRequestAverage)+osa1.RAMBytesRequestAverage, sa2.RAMBytesRequestAverage)
  114. }
  115. if !util.IsApproximately(sa2.RAMBytesUsageAverage, (0.5*osa2.RAMBytesUsageAverage)+osa1.RAMBytesUsageAverage) {
  116. t.Fatalf("incorrect RAMBytesUsageAverage: expected %.5f; actual %.5f", (0.5*osa2.RAMBytesUsageAverage)+osa1.RAMBytesRequestAverage, sa2.RAMBytesUsageAverage)
  117. }
  118. if !util.IsApproximately(sa2.CPUCost, osa2.CPUCost+osa1.CPUCost) {
  119. t.Fatalf("incorrect CPUCost: expected %.5f; actual %.5f", osa2.CPUCost+osa1.CPUCost, sa2.CPUCost)
  120. }
  121. if !util.IsApproximately(sa2.GPUCost, osa2.GPUCost+osa1.GPUCost) {
  122. t.Fatalf("incorrect GPUCost: expected %.5f; actual %.5f", osa2.GPUCost+osa1.GPUCost, sa2.GPUCost)
  123. }
  124. if !util.IsApproximately(sa2.NetworkCost, osa2.NetworkCost+osa1.NetworkCost) {
  125. t.Fatalf("incorrect NetworkCost: expected %.5f; actual %.5f", osa2.NetworkCost+osa1.NetworkCost, sa2.NetworkCost)
  126. }
  127. if !util.IsApproximately(sa2.LoadBalancerCost, osa2.LoadBalancerCost+osa1.LoadBalancerCost) {
  128. t.Fatalf("incorrect LoadBalancerCost: expected %.5f; actual %.5f", osa2.LoadBalancerCost+osa1.LoadBalancerCost, sa2.LoadBalancerCost)
  129. }
  130. if !util.IsApproximately(sa2.PVCost, osa2.PVCost+osa1.PVCost) {
  131. t.Fatalf("incorrect PVCost: expected %.5f; actual %.5f", osa2.PVCost+osa1.PVCost, sa2.PVCost)
  132. }
  133. if !util.IsApproximately(sa2.RAMCost, osa2.RAMCost+osa1.RAMCost) {
  134. t.Fatalf("incorrect RAMCost: expected %.5f; actual %.5f", osa2.RAMCost+osa1.RAMCost, sa2.RAMCost)
  135. }
  136. if !util.IsApproximately(sa2.SharedCost, osa2.SharedCost+osa1.SharedCost) {
  137. t.Fatalf("incorrect SharedCost: expected %.5f; actual %.5f", osa2.SharedCost+osa1.SharedCost, sa2.SharedCost)
  138. }
  139. if !util.IsApproximately(sa2.ExternalCost, osa2.ExternalCost+osa1.ExternalCost) {
  140. t.Fatalf("incorrect ExternalCost: expected %.5f; actual %.5f", osa2.ExternalCost+osa1.ExternalCost, sa2.ExternalCost)
  141. }
  142. })
  143. // reset
  144. sa1 = osa1.Clone()
  145. sa2 = osa2.Clone()
  146. // add sa2 to sa1 and expect same averages, but double costs
  147. t.Run("sa1.Add(sa2)", func(t *testing.T) {
  148. err = sa1.Add(sa2)
  149. if err != nil {
  150. t.Fatalf("unexpected error: %s", err)
  151. }
  152. if sa1.Properties != nil {
  153. t.Fatalf("expected properties to be nil; actual: %s", sa1.Properties)
  154. }
  155. if !util.IsApproximately(sa1.CPUCoreRequestAverage, (0.5*osa2.CPUCoreRequestAverage)+osa1.CPUCoreRequestAverage) {
  156. t.Fatalf("incorrect CPUCoreRequestAverage: expected %.5f; actual %.5f", (0.5*osa2.CPUCoreRequestAverage)+osa1.CPUCoreRequestAverage, sa2.CPUCoreRequestAverage)
  157. }
  158. if !util.IsApproximately(sa1.CPUCoreUsageAverage, (0.5*osa2.CPUCoreUsageAverage)+osa1.CPUCoreUsageAverage) {
  159. t.Fatalf("incorrect CPUCoreUsageAverage: expected %.5f; actual %.5f", (0.5*osa2.CPUCoreUsageAverage)+osa1.CPUCoreRequestAverage, sa2.CPUCoreUsageAverage)
  160. }
  161. if !util.IsApproximately(sa1.RAMBytesRequestAverage, (0.5*osa2.RAMBytesRequestAverage)+osa1.RAMBytesRequestAverage) {
  162. t.Fatalf("incorrect RAMBytesRequestAverage: expected %.5f; actual %.5f", (0.5*osa2.RAMBytesRequestAverage)+osa1.RAMBytesRequestAverage, sa2.RAMBytesRequestAverage)
  163. }
  164. if !util.IsApproximately(sa1.RAMBytesUsageAverage, (0.5*osa2.RAMBytesUsageAverage)+osa1.RAMBytesUsageAverage) {
  165. t.Fatalf("incorrect RAMBytesUsageAverage: expected %.5f; actual %.5f", (0.5*osa2.RAMBytesUsageAverage)+osa1.RAMBytesRequestAverage, sa2.RAMBytesUsageAverage)
  166. }
  167. if !util.IsApproximately(sa1.CPUCost, osa2.CPUCost+osa1.CPUCost) {
  168. t.Fatalf("incorrect CPUCost: expected %.5f; actual %.5f", osa2.CPUCost+osa1.CPUCost, sa2.CPUCost)
  169. }
  170. if !util.IsApproximately(sa1.GPUCost, osa2.GPUCost+osa1.GPUCost) {
  171. t.Fatalf("incorrect GPUCost: expected %.5f; actual %.5f", osa2.GPUCost+osa1.GPUCost, sa2.GPUCost)
  172. }
  173. if !util.IsApproximately(sa1.NetworkCost, osa2.NetworkCost+osa1.NetworkCost) {
  174. t.Fatalf("incorrect NetworkCost: expected %.5f; actual %.5f", osa2.NetworkCost+osa1.NetworkCost, sa2.NetworkCost)
  175. }
  176. if !util.IsApproximately(sa1.LoadBalancerCost, osa2.LoadBalancerCost+osa1.LoadBalancerCost) {
  177. t.Fatalf("incorrect LoadBalancerCost: expected %.5f; actual %.5f", osa2.LoadBalancerCost+osa1.LoadBalancerCost, sa2.LoadBalancerCost)
  178. }
  179. if !util.IsApproximately(sa1.PVCost, osa2.PVCost+osa1.PVCost) {
  180. t.Fatalf("incorrect PVCost: expected %.5f; actual %.5f", osa2.PVCost+osa1.PVCost, sa2.PVCost)
  181. }
  182. if !util.IsApproximately(sa1.RAMCost, osa2.RAMCost+osa1.RAMCost) {
  183. t.Fatalf("incorrect RAMCost: expected %.5f; actual %.5f", osa2.RAMCost+osa1.RAMCost, sa2.RAMCost)
  184. }
  185. if !util.IsApproximately(sa1.SharedCost, osa2.SharedCost+osa1.SharedCost) {
  186. t.Fatalf("incorrect SharedCost: expected %.5f; actual %.5f", osa2.SharedCost+osa1.SharedCost, sa2.SharedCost)
  187. }
  188. if !util.IsApproximately(sa1.ExternalCost, osa2.ExternalCost+osa1.ExternalCost) {
  189. t.Fatalf("incorrect ExternalCost: expected %.5f; actual %.5f", osa2.ExternalCost+osa1.ExternalCost, sa2.ExternalCost)
  190. }
  191. })
  192. }
  193. func TestSummaryAllocationSet_RAMEfficiency(t *testing.T) {
  194. // Generating 6 sample summary allocations for testing
  195. var sa1, sa2, sa3, sa4, sa5, sa6 *SummaryAllocation
  196. // Generating accumulated summary allocation sets for testing
  197. var sas1, sas2, sas3, sas4, sas5 *SummaryAllocationSet
  198. window, _ := ParseWindowUTC("7d")
  199. saStart := *window.Start()
  200. saEnd := *window.End()
  201. sa1 = &SummaryAllocation{
  202. Name: "cluster1/namespace1/pod1/container1",
  203. Properties: &AllocationProperties{
  204. Cluster: "cluster1",
  205. Namespace: "namespace1",
  206. Pod: "pod1",
  207. Container: "container1",
  208. },
  209. Start: saStart,
  210. End: saEnd,
  211. RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
  212. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  213. RAMCost: 0.05,
  214. }
  215. sa2 = &SummaryAllocation{
  216. Name: "cluster1/namespace1/pod1/container2",
  217. Properties: &AllocationProperties{
  218. Cluster: "cluster1",
  219. Namespace: "namespace1",
  220. Pod: "pod1",
  221. Container: "container2",
  222. },
  223. Start: saStart,
  224. End: saEnd,
  225. RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
  226. RAMBytesUsageAverage: 15.0 * 1024.0 * 1024.0,
  227. RAMCost: 0.10,
  228. }
  229. sa3 = &SummaryAllocation{
  230. Name: "cluster1/namespace1/pod1/container3",
  231. Properties: &AllocationProperties{
  232. Cluster: "cluster1",
  233. Namespace: "namespace1",
  234. Pod: "pod1",
  235. Container: "container3",
  236. },
  237. Start: saStart,
  238. End: saEnd,
  239. RAMBytesRequestAverage: 0.0,
  240. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  241. RAMCost: 0.0,
  242. }
  243. sa4 = &SummaryAllocation{
  244. Name: "cluster1/namespace1/pod1/container4",
  245. Properties: &AllocationProperties{
  246. Cluster: "cluster1",
  247. Namespace: "namespace1",
  248. Pod: "pod1",
  249. Container: "container4",
  250. },
  251. Start: saStart,
  252. End: saEnd,
  253. RAMBytesRequestAverage: 0.0,
  254. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  255. RAMCost: 0.0,
  256. }
  257. sa5 = &SummaryAllocation{
  258. Name: "cluster1/namespace1/pod1/container4",
  259. Properties: &AllocationProperties{
  260. Cluster: "cluster1",
  261. Namespace: "namespace1",
  262. Pod: "pod1",
  263. Container: "container5",
  264. },
  265. Start: saStart,
  266. End: saEnd,
  267. RAMBytesRequestAverage: 0.0,
  268. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  269. RAMCost: 0.10,
  270. }
  271. sa6 = &SummaryAllocation{
  272. Name: "cluster1/namespace1/pod1/container4",
  273. Properties: &AllocationProperties{
  274. Cluster: "cluster1",
  275. Namespace: "namespace1",
  276. Pod: "pod1",
  277. Container: "container6",
  278. },
  279. Start: saStart,
  280. End: saEnd,
  281. RAMBytesRequestAverage: 0.0,
  282. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  283. RAMCost: 0.10,
  284. }
  285. testcase1Map := map[string]*SummaryAllocation{
  286. "cluster1/namespace1/pod1/container1": sa1,
  287. "cluster1/namespace1/pod1/container2": sa2,
  288. }
  289. testcase2Map := map[string]*SummaryAllocation{
  290. "cluster1/namespace1/pod1/container3": sa3,
  291. "cluster1/namespace1/pod1/container4": sa4,
  292. }
  293. testcase3Map := map[string]*SummaryAllocation{
  294. "cluster1/namespace1/pod1/container5": sa5,
  295. "cluster1/namespace1/pod1/container6": sa6,
  296. }
  297. testcase4Map := map[string]*SummaryAllocation{}
  298. testcase5Map := map[string]*SummaryAllocation{
  299. "cluster1/namespace1/pod1/container1": sa1,
  300. "cluster1/namespace1/pod1/container2": sa2,
  301. "cluster1/namespace1/pod1/container3": sa3,
  302. "cluster1/namespace1/pod1/container4": sa4,
  303. "cluster1/namespace1/pod1/container5": sa5,
  304. "cluster1/namespace1/pod1/container6": sa6,
  305. }
  306. sas1 = &SummaryAllocationSet{
  307. SummaryAllocations: testcase1Map,
  308. Window: window,
  309. }
  310. sas2 = &SummaryAllocationSet{
  311. SummaryAllocations: testcase2Map,
  312. Window: window,
  313. }
  314. sas3 = &SummaryAllocationSet{
  315. SummaryAllocations: testcase3Map,
  316. Window: window,
  317. }
  318. sas4 = &SummaryAllocationSet{
  319. SummaryAllocations: testcase4Map,
  320. Window: window,
  321. }
  322. sas5 = &SummaryAllocationSet{
  323. SummaryAllocations: testcase5Map,
  324. Window: window,
  325. }
  326. cases := []struct {
  327. name string
  328. testsas *SummaryAllocationSet
  329. expectedEfficiency float64
  330. }{
  331. {
  332. name: "Check RAMEfficiency when totalRAMBytesRequest over allocation summary set is greater than 0",
  333. testsas: sas1,
  334. expectedEfficiency: 0.25,
  335. },
  336. {
  337. name: "Check RAMEfficiency when totalRAMBytesRequest is 0 and totalRAMCost or totalRAMBytesUsage equal to 0",
  338. testsas: sas2,
  339. expectedEfficiency: 0.0,
  340. },
  341. {
  342. name: "Check RAMEfficiency when totalRAMBytesRequest is 0 and totalRAMCost or totalRAMBytesUsage is not 0",
  343. testsas: sas3,
  344. expectedEfficiency: 1.0,
  345. },
  346. {
  347. name: "Check RAMEfficiency when allocation summary set is empty",
  348. testsas: sas4,
  349. expectedEfficiency: 0.0,
  350. },
  351. {
  352. name: "Check RAMEfficiency over combination of all allocation summaries",
  353. testsas: sas5,
  354. expectedEfficiency: 0.65,
  355. },
  356. }
  357. for _, c := range cases {
  358. t.Run(c.name, func(t *testing.T) {
  359. returnEfficiency := c.testsas.RAMEfficiency()
  360. if !util.IsApproximately(c.expectedEfficiency, returnEfficiency) {
  361. t.Errorf("Case %s failed: Expected RAM Efficiency %.2f but got RAM Efficiency of as %.2f", c.name, c.expectedEfficiency, returnEfficiency)
  362. t.Fail()
  363. }
  364. })
  365. }
  366. }
  367. func TestSummaryAllocationSet_CPUEfficiency(t *testing.T) {
  368. // Generating 6 sample summary allocations for testing
  369. var sa1, sa2, sa3, sa4, sa5, sa6 *SummaryAllocation
  370. // Generating accumulated summary allocation sets for testing
  371. var sas1, sas2, sas3, sas4, sas5 *SummaryAllocationSet
  372. window, _ := ParseWindowUTC("7d")
  373. saStart := *window.Start()
  374. saEnd := *window.End()
  375. sa1 = &SummaryAllocation{
  376. Name: "cluster1/namespace1/pod1/container1",
  377. Properties: &AllocationProperties{
  378. Cluster: "cluster1",
  379. Namespace: "namespace1",
  380. Pod: "pod1",
  381. Container: "container1",
  382. },
  383. Start: saStart,
  384. End: saEnd,
  385. CPUCoreRequestAverage: 0.5,
  386. CPUCoreUsageAverage: 0.1,
  387. CPUCost: 0.2,
  388. }
  389. sa2 = &SummaryAllocation{
  390. Name: "cluster1/namespace1/pod1/container2",
  391. Properties: &AllocationProperties{
  392. Cluster: "cluster1",
  393. Namespace: "namespace1",
  394. Pod: "pod1",
  395. Container: "container2",
  396. },
  397. Start: saStart,
  398. End: saEnd,
  399. CPUCoreRequestAverage: 0.5,
  400. CPUCoreUsageAverage: 0.2,
  401. CPUCost: 0.2,
  402. }
  403. sa3 = &SummaryAllocation{
  404. Name: "cluster1/namespace1/pod1/container3",
  405. Properties: &AllocationProperties{
  406. Cluster: "cluster1",
  407. Namespace: "namespace1",
  408. Pod: "pod1",
  409. Container: "container3",
  410. },
  411. Start: saStart,
  412. End: saEnd,
  413. CPUCoreRequestAverage: 0.0,
  414. CPUCoreUsageAverage: 0.0,
  415. CPUCost: 1.0,
  416. }
  417. sa4 = &SummaryAllocation{
  418. Name: "cluster1/namespace1/pod1/container4",
  419. Properties: &AllocationProperties{
  420. Cluster: "cluster1",
  421. Namespace: "namespace1",
  422. Pod: "pod1",
  423. Container: "container4",
  424. },
  425. Start: saStart,
  426. End: saEnd,
  427. CPUCoreRequestAverage: 0.0,
  428. CPUCoreUsageAverage: 0.0,
  429. CPUCost: 2.0,
  430. }
  431. sa5 = &SummaryAllocation{
  432. Name: "cluster1/namespace1/pod1/container4",
  433. Properties: &AllocationProperties{
  434. Cluster: "cluster1",
  435. Namespace: "namespace1",
  436. Pod: "pod1",
  437. Container: "container5",
  438. },
  439. Start: saStart,
  440. End: saEnd,
  441. CPUCoreRequestAverage: 0.0,
  442. CPUCoreUsageAverage: 0.1,
  443. CPUCost: 0.2,
  444. }
  445. sa6 = &SummaryAllocation{
  446. Name: "cluster1/namespace1/pod1/container4",
  447. Properties: &AllocationProperties{
  448. Cluster: "cluster1",
  449. Namespace: "namespace1",
  450. Pod: "pod1",
  451. Container: "container6",
  452. },
  453. Start: saStart,
  454. End: saEnd,
  455. CPUCoreRequestAverage: 0.0,
  456. CPUCoreUsageAverage: 0.1,
  457. CPUCost: 0.2,
  458. }
  459. testcase1Map := map[string]*SummaryAllocation{
  460. "cluster1/namespace1/pod1/container1": sa1,
  461. "cluster1/namespace1/pod1/container2": sa2,
  462. }
  463. testcase2Map := map[string]*SummaryAllocation{
  464. "cluster1/namespace1/pod1/container3": sa3,
  465. "cluster1/namespace1/pod1/container4": sa4,
  466. }
  467. testcase3Map := map[string]*SummaryAllocation{
  468. "cluster1/namespace1/pod1/container5": sa5,
  469. "cluster1/namespace1/pod1/container6": sa6,
  470. }
  471. testcase4Map := map[string]*SummaryAllocation{}
  472. testcase5Map := map[string]*SummaryAllocation{
  473. "cluster1/namespace1/pod1/container1": sa1,
  474. "cluster1/namespace1/pod1/container2": sa2,
  475. "cluster1/namespace1/pod1/container3": sa3,
  476. "cluster1/namespace1/pod1/container4": sa4,
  477. "cluster1/namespace1/pod1/container5": sa5,
  478. "cluster1/namespace1/pod1/container6": sa6,
  479. }
  480. sas1 = &SummaryAllocationSet{
  481. SummaryAllocations: testcase1Map,
  482. Window: window,
  483. }
  484. sas2 = &SummaryAllocationSet{
  485. SummaryAllocations: testcase2Map,
  486. Window: window,
  487. }
  488. sas3 = &SummaryAllocationSet{
  489. SummaryAllocations: testcase3Map,
  490. Window: window,
  491. }
  492. sas4 = &SummaryAllocationSet{
  493. SummaryAllocations: testcase4Map,
  494. Window: window,
  495. }
  496. sas5 = &SummaryAllocationSet{
  497. SummaryAllocations: testcase5Map,
  498. Window: window,
  499. }
  500. cases := []struct {
  501. name string
  502. testsas *SummaryAllocationSet
  503. expectedEfficiency float64
  504. }{
  505. {
  506. name: "Check CPUEfficiency when totalCPUCoreRequest is greater than 0 over allocation summary set",
  507. testsas: sas1,
  508. expectedEfficiency: 0.30,
  509. },
  510. {
  511. name: "Check CPUEfficiency when totalCPUCoreRequest is 0 and totalCPUCost or totalCPUCoreUsage equal to 0",
  512. testsas: sas2,
  513. expectedEfficiency: 0.0,
  514. },
  515. {
  516. name: "Check CPUEfficiency when totalCPUCoreRequest is 0 and totalCPUCost or totalCPUCoreUsage is not 0",
  517. testsas: sas3,
  518. expectedEfficiency: 1.0,
  519. },
  520. {
  521. name: "Check CPUEfficiency when allocation summary set is empty",
  522. testsas: sas4,
  523. expectedEfficiency: 0.0,
  524. },
  525. {
  526. name: "Check CPUEfficiency over combination of all allocation summaries",
  527. testsas: sas5,
  528. expectedEfficiency: 0.50,
  529. },
  530. }
  531. for _, c := range cases {
  532. t.Run(c.name, func(t *testing.T) {
  533. returnEfficiency := c.testsas.CPUEfficiency()
  534. if !util.IsApproximately(c.expectedEfficiency, returnEfficiency) {
  535. t.Errorf("Case %s failed: Expected CPU Efficiency %.2f but got CPU Efficiency of as %.2f", c.name, c.expectedEfficiency, returnEfficiency)
  536. t.Fail()
  537. }
  538. })
  539. }
  540. }
  541. func TestSummaryAllocationSet_TotalEfficiency(t *testing.T) {
  542. // Generating 6 sample summary allocations for testing
  543. var sa1, sa2, sa3, sa4, sa5, sa6, idlesa *SummaryAllocation
  544. // Generating accumulated summary allocation sets for testing
  545. var sas1, sas2, sas3, sas4 *SummaryAllocationSet
  546. window, _ := ParseWindowUTC("7d")
  547. saStart := *window.Start()
  548. saEnd := *window.End()
  549. sa1 = &SummaryAllocation{
  550. Name: "cluster1/namespace1/pod1/container1",
  551. Properties: &AllocationProperties{
  552. Cluster: "cluster1",
  553. Namespace: "namespace1",
  554. Pod: "pod1",
  555. Container: "container1",
  556. },
  557. Start: saStart,
  558. End: saEnd,
  559. CPUCoreRequestAverage: 0.5,
  560. CPUCoreUsageAverage: 0.1,
  561. CPUCost: 0.0,
  562. RAMBytesRequestAverage: 0.0,
  563. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  564. RAMCost: 0.0,
  565. }
  566. sa2 = &SummaryAllocation{
  567. Name: "cluster1/namespace1/pod1/container2",
  568. Properties: &AllocationProperties{
  569. Cluster: "cluster1",
  570. Namespace: "namespace1",
  571. Pod: "pod1",
  572. Container: "container2",
  573. },
  574. Start: saStart,
  575. End: saEnd,
  576. CPUCoreRequestAverage: 0.5,
  577. CPUCoreUsageAverage: 0.2,
  578. CPUCost: 0.0,
  579. RAMBytesRequestAverage: 0.0,
  580. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  581. RAMCost: 0.0,
  582. }
  583. sa3 = &SummaryAllocation{
  584. Name: "cluster1/namespace1/pod1/container3",
  585. Properties: &AllocationProperties{
  586. Cluster: "cluster1",
  587. Namespace: "namespace1",
  588. Pod: "pod1",
  589. Container: "container3",
  590. },
  591. Start: saStart,
  592. End: saEnd,
  593. CPUCoreRequestAverage: 0.5,
  594. CPUCoreUsageAverage: 0.2,
  595. CPUCost: 1.0,
  596. RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
  597. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  598. RAMCost: 1.0,
  599. }
  600. sa4 = &SummaryAllocation{
  601. Name: "cluster1/namespace1/pod1/container4",
  602. Properties: &AllocationProperties{
  603. Cluster: "cluster1",
  604. Namespace: "namespace1",
  605. Pod: "pod1",
  606. Container: "container4",
  607. },
  608. Start: saStart,
  609. End: saEnd,
  610. CPUCoreRequestAverage: 0.5,
  611. CPUCoreUsageAverage: 0.1,
  612. CPUCost: 1.0,
  613. RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
  614. RAMBytesUsageAverage: 20.0 * 1024.0 * 1024.0,
  615. RAMCost: 1.0,
  616. }
  617. sa5 = &SummaryAllocation{
  618. Name: "cluster1/namespace1/pod1/container4",
  619. Properties: &AllocationProperties{
  620. Cluster: "cluster1",
  621. Namespace: "namespace1",
  622. Pod: "pod1",
  623. Container: "container5",
  624. },
  625. Start: saStart,
  626. End: saEnd,
  627. CPUCoreRequestAverage: 0.5,
  628. CPUCoreUsageAverage: 0.1,
  629. CPUCost: 1.0,
  630. RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
  631. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  632. RAMCost: 1.0,
  633. }
  634. sa6 = &SummaryAllocation{
  635. Name: "cluster1/namespace1/pod1/container4",
  636. Properties: &AllocationProperties{
  637. Cluster: "cluster1",
  638. Namespace: "namespace1",
  639. Pod: "pod1",
  640. Container: "container6",
  641. },
  642. Start: saStart,
  643. End: saEnd,
  644. CPUCoreRequestAverage: 0.5,
  645. CPUCoreUsageAverage: 0.2,
  646. CPUCost: 1.0,
  647. RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
  648. RAMBytesUsageAverage: 20.0 * 1024.0 * 1024.0,
  649. RAMCost: 1.0,
  650. }
  651. idlesa = &SummaryAllocation{
  652. Name: IdleSuffix,
  653. Properties: &AllocationProperties{
  654. Cluster: "cluster1",
  655. Namespace: "namespace1",
  656. Pod: "pod1",
  657. Container: "container7",
  658. },
  659. Start: saStart,
  660. End: saEnd,
  661. CPUCost: 1.0,
  662. RAMCost: 1.0,
  663. }
  664. testcase1Map := map[string]*SummaryAllocation{
  665. "cluster1/namespace1/pod1/container1": sa1,
  666. "cluster1/namespace1/pod1/container2": sa2,
  667. }
  668. testcase2Map := map[string]*SummaryAllocation{}
  669. testcase3Map := map[string]*SummaryAllocation{
  670. "cluster1/namespace1/pod1/container3": sa3,
  671. "cluster1/namespace1/pod1/container4": sa4,
  672. "cluster1/namespace1/pod1/container5": sa5,
  673. "cluster1/namespace1/pod1/container6": sa6,
  674. }
  675. testcase4Map := map[string]*SummaryAllocation{
  676. "cluster1/namespace1/pod1/container5": sa5,
  677. "cluster1/namespace1/pod1/container6": sa6,
  678. "cluster1/__idle__": idlesa,
  679. }
  680. sas1 = &SummaryAllocationSet{
  681. SummaryAllocations: testcase1Map,
  682. Window: window,
  683. }
  684. sas2 = &SummaryAllocationSet{
  685. SummaryAllocations: testcase2Map,
  686. Window: window,
  687. }
  688. sas3 = &SummaryAllocationSet{
  689. SummaryAllocations: testcase3Map,
  690. Window: window,
  691. }
  692. sas4 = &SummaryAllocationSet{
  693. SummaryAllocations: testcase4Map,
  694. Window: window,
  695. }
  696. cases := []struct {
  697. name string
  698. testsas *SummaryAllocationSet
  699. expectedEfficiency float64
  700. }{
  701. {
  702. name: "When TotalEfficiency when sum of TotalRAMCost and TotalCPUCost is 0",
  703. testsas: sas1,
  704. expectedEfficiency: 0.0,
  705. },
  706. {
  707. name: "Check TotalEfficiency when allocation summary set is empty",
  708. testsas: sas2,
  709. expectedEfficiency: 0.0,
  710. },
  711. {
  712. name: "Check TotalEfficiency over all 4 allocation summaries",
  713. testsas: sas3,
  714. expectedEfficiency: 0.30,
  715. },
  716. {
  717. name: "Check TotalEfficiency with idle cost",
  718. testsas: sas4,
  719. expectedEfficiency: 0.20,
  720. },
  721. }
  722. for _, c := range cases {
  723. t.Run(c.name, func(t *testing.T) {
  724. returnEfficiency := c.testsas.TotalEfficiency()
  725. if !util.IsApproximately(c.expectedEfficiency, returnEfficiency) {
  726. t.Errorf("Case %s failed: Expected Total Efficiency %.2f but got Total Efficiency of as %.2f", c.name, c.expectedEfficiency, returnEfficiency)
  727. t.Fail()
  728. }
  729. })
  730. }
  731. }