summaryallocation_test.go 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197
  1. package kubecost
  2. import (
  3. "math"
  4. "reflect"
  5. "testing"
  6. "time"
  7. "github.com/opencost/opencost/pkg/util"
  8. )
  9. func TestSummaryAllocation_Add(t *testing.T) {
  10. window, _ := ParseWindowUTC("yesterday")
  11. var sa1, sa2, osa1, osa2, nilsa *SummaryAllocation
  12. var err error
  13. sa1Start := *window.Start()
  14. sa1End := *window.End()
  15. sa1 = &SummaryAllocation{
  16. Name: "cluster1/namespace1/pod1/container1",
  17. Properties: &AllocationProperties{
  18. Cluster: "cluster1",
  19. Namespace: "namespace1",
  20. Pod: "pod1",
  21. Container: "container1",
  22. },
  23. Start: sa1Start,
  24. End: sa1End,
  25. CPUCoreRequestAverage: 0.5,
  26. CPUCoreUsageAverage: 0.1,
  27. CPUCost: 0.2,
  28. GPUCost: 1.0,
  29. NetworkCost: 0.1,
  30. LoadBalancerCost: 0.6,
  31. PVCost: 0.005,
  32. RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
  33. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  34. RAMCost: 0.05,
  35. SharedCost: 1.0,
  36. ExternalCost: 1.0,
  37. }
  38. osa1 = sa1.Clone()
  39. // sa2 is just as expensive, with twice as much usage and request, and half
  40. // the time compared to sa1
  41. sa2Start := *window.Start()
  42. sa2Start = sa2Start.Add(6 * time.Hour)
  43. sa2End := *window.End()
  44. sa2End = sa2End.Add(-6 * time.Hour)
  45. sa2 = &SummaryAllocation{
  46. Name: "cluster1/namespace1/pod2/container2",
  47. Properties: &AllocationProperties{
  48. Cluster: "cluster1",
  49. Namespace: "namespace1",
  50. Pod: "pod2",
  51. Container: "container2",
  52. },
  53. Start: sa2Start,
  54. End: sa2End,
  55. CPUCoreRequestAverage: sa1.CPUCoreRequestAverage * 2.0,
  56. CPUCoreUsageAverage: sa1.CPUCoreUsageAverage * 2.0,
  57. CPUCost: sa1.CPUCost,
  58. GPUCost: sa1.GPUCost,
  59. NetworkCost: sa1.NetworkCost,
  60. LoadBalancerCost: sa1.LoadBalancerCost,
  61. PVCost: sa1.PVCost,
  62. RAMBytesRequestAverage: sa1.RAMBytesRequestAverage * 2.0,
  63. RAMBytesUsageAverage: sa1.RAMBytesUsageAverage * 2.0,
  64. RAMCost: sa1.RAMCost,
  65. SharedCost: sa1.SharedCost,
  66. ExternalCost: sa1.ExternalCost,
  67. }
  68. osa2 = sa2.Clone()
  69. // add nil to nil, expect and error
  70. t.Run("nil.Add(nil)", func(t *testing.T) {
  71. err = nilsa.Add(nilsa)
  72. if err == nil {
  73. t.Fatalf("expected error: cannot add nil SummaryAllocations")
  74. }
  75. })
  76. // reset
  77. sa1 = osa1.Clone()
  78. sa2 = osa2.Clone()
  79. // add sa1 to nil, expect and error
  80. t.Run("nil.Add(sa1)", func(t *testing.T) {
  81. err = nilsa.Add(sa1)
  82. if err == nil {
  83. t.Fatalf("expected error: cannot add nil SummaryAllocations")
  84. }
  85. })
  86. // reset
  87. sa1 = osa1.Clone()
  88. sa2 = osa2.Clone()
  89. // add nil to sa1, expect and error
  90. t.Run("sa1.Add(nil)", func(t *testing.T) {
  91. err = sa1.Add(nilsa)
  92. if err == nil {
  93. t.Fatalf("expected error: cannot add nil SummaryAllocations")
  94. }
  95. })
  96. // reset
  97. sa1 = osa1.Clone()
  98. sa2 = osa2.Clone()
  99. // add sa1 to sa2 and expect same averages, but double costs
  100. t.Run("sa2.Add(sa1)", func(t *testing.T) {
  101. err = sa2.Add(sa1)
  102. if err != nil {
  103. t.Fatalf("unexpected error: %s", err)
  104. }
  105. if sa2.Properties != nil {
  106. t.Fatalf("expected properties to be nil; actual: %s", sa1.Properties)
  107. }
  108. if !util.IsApproximately(sa2.CPUCoreRequestAverage, (0.5*osa2.CPUCoreRequestAverage)+osa1.CPUCoreRequestAverage) {
  109. t.Fatalf("incorrect CPUCoreRequestAverage: expected %.5f; actual %.5f", (0.5*osa2.CPUCoreRequestAverage)+osa1.CPUCoreRequestAverage, sa2.CPUCoreRequestAverage)
  110. }
  111. if !util.IsApproximately(sa2.CPUCoreUsageAverage, (0.5*osa2.CPUCoreUsageAverage)+osa1.CPUCoreUsageAverage) {
  112. t.Fatalf("incorrect CPUCoreUsageAverage: expected %.5f; actual %.5f", (0.5*osa2.CPUCoreUsageAverage)+osa1.CPUCoreRequestAverage, sa2.CPUCoreUsageAverage)
  113. }
  114. if !util.IsApproximately(sa2.RAMBytesRequestAverage, (0.5*osa2.RAMBytesRequestAverage)+osa1.RAMBytesRequestAverage) {
  115. t.Fatalf("incorrect RAMBytesRequestAverage: expected %.5f; actual %.5f", (0.5*osa2.RAMBytesRequestAverage)+osa1.RAMBytesRequestAverage, sa2.RAMBytesRequestAverage)
  116. }
  117. if !util.IsApproximately(sa2.RAMBytesUsageAverage, (0.5*osa2.RAMBytesUsageAverage)+osa1.RAMBytesUsageAverage) {
  118. t.Fatalf("incorrect RAMBytesUsageAverage: expected %.5f; actual %.5f", (0.5*osa2.RAMBytesUsageAverage)+osa1.RAMBytesRequestAverage, sa2.RAMBytesUsageAverage)
  119. }
  120. if !util.IsApproximately(sa2.CPUCost, osa2.CPUCost+osa1.CPUCost) {
  121. t.Fatalf("incorrect CPUCost: expected %.5f; actual %.5f", osa2.CPUCost+osa1.CPUCost, sa2.CPUCost)
  122. }
  123. if !util.IsApproximately(sa2.GPUCost, osa2.GPUCost+osa1.GPUCost) {
  124. t.Fatalf("incorrect GPUCost: expected %.5f; actual %.5f", osa2.GPUCost+osa1.GPUCost, sa2.GPUCost)
  125. }
  126. if !util.IsApproximately(sa2.NetworkCost, osa2.NetworkCost+osa1.NetworkCost) {
  127. t.Fatalf("incorrect NetworkCost: expected %.5f; actual %.5f", osa2.NetworkCost+osa1.NetworkCost, sa2.NetworkCost)
  128. }
  129. if !util.IsApproximately(sa2.LoadBalancerCost, osa2.LoadBalancerCost+osa1.LoadBalancerCost) {
  130. t.Fatalf("incorrect LoadBalancerCost: expected %.5f; actual %.5f", osa2.LoadBalancerCost+osa1.LoadBalancerCost, sa2.LoadBalancerCost)
  131. }
  132. if !util.IsApproximately(sa2.PVCost, osa2.PVCost+osa1.PVCost) {
  133. t.Fatalf("incorrect PVCost: expected %.5f; actual %.5f", osa2.PVCost+osa1.PVCost, sa2.PVCost)
  134. }
  135. if !util.IsApproximately(sa2.RAMCost, osa2.RAMCost+osa1.RAMCost) {
  136. t.Fatalf("incorrect RAMCost: expected %.5f; actual %.5f", osa2.RAMCost+osa1.RAMCost, sa2.RAMCost)
  137. }
  138. if !util.IsApproximately(sa2.SharedCost, osa2.SharedCost+osa1.SharedCost) {
  139. t.Fatalf("incorrect SharedCost: expected %.5f; actual %.5f", osa2.SharedCost+osa1.SharedCost, sa2.SharedCost)
  140. }
  141. if !util.IsApproximately(sa2.ExternalCost, osa2.ExternalCost+osa1.ExternalCost) {
  142. t.Fatalf("incorrect ExternalCost: expected %.5f; actual %.5f", osa2.ExternalCost+osa1.ExternalCost, sa2.ExternalCost)
  143. }
  144. })
  145. // reset
  146. sa1 = osa1.Clone()
  147. sa2 = osa2.Clone()
  148. // add sa2 to sa1 and expect same averages, but double costs
  149. t.Run("sa1.Add(sa2)", func(t *testing.T) {
  150. err = sa1.Add(sa2)
  151. if err != nil {
  152. t.Fatalf("unexpected error: %s", err)
  153. }
  154. if sa1.Properties != nil {
  155. t.Fatalf("expected properties to be nil; actual: %s", sa1.Properties)
  156. }
  157. if !util.IsApproximately(sa1.CPUCoreRequestAverage, (0.5*osa2.CPUCoreRequestAverage)+osa1.CPUCoreRequestAverage) {
  158. t.Fatalf("incorrect CPUCoreRequestAverage: expected %.5f; actual %.5f", (0.5*osa2.CPUCoreRequestAverage)+osa1.CPUCoreRequestAverage, sa2.CPUCoreRequestAverage)
  159. }
  160. if !util.IsApproximately(sa1.CPUCoreUsageAverage, (0.5*osa2.CPUCoreUsageAverage)+osa1.CPUCoreUsageAverage) {
  161. t.Fatalf("incorrect CPUCoreUsageAverage: expected %.5f; actual %.5f", (0.5*osa2.CPUCoreUsageAverage)+osa1.CPUCoreRequestAverage, sa2.CPUCoreUsageAverage)
  162. }
  163. if !util.IsApproximately(sa1.RAMBytesRequestAverage, (0.5*osa2.RAMBytesRequestAverage)+osa1.RAMBytesRequestAverage) {
  164. t.Fatalf("incorrect RAMBytesRequestAverage: expected %.5f; actual %.5f", (0.5*osa2.RAMBytesRequestAverage)+osa1.RAMBytesRequestAverage, sa2.RAMBytesRequestAverage)
  165. }
  166. if !util.IsApproximately(sa1.RAMBytesUsageAverage, (0.5*osa2.RAMBytesUsageAverage)+osa1.RAMBytesUsageAverage) {
  167. t.Fatalf("incorrect RAMBytesUsageAverage: expected %.5f; actual %.5f", (0.5*osa2.RAMBytesUsageAverage)+osa1.RAMBytesRequestAverage, sa2.RAMBytesUsageAverage)
  168. }
  169. if !util.IsApproximately(sa1.CPUCost, osa2.CPUCost+osa1.CPUCost) {
  170. t.Fatalf("incorrect CPUCost: expected %.5f; actual %.5f", osa2.CPUCost+osa1.CPUCost, sa2.CPUCost)
  171. }
  172. if !util.IsApproximately(sa1.GPUCost, osa2.GPUCost+osa1.GPUCost) {
  173. t.Fatalf("incorrect GPUCost: expected %.5f; actual %.5f", osa2.GPUCost+osa1.GPUCost, sa2.GPUCost)
  174. }
  175. if !util.IsApproximately(sa1.NetworkCost, osa2.NetworkCost+osa1.NetworkCost) {
  176. t.Fatalf("incorrect NetworkCost: expected %.5f; actual %.5f", osa2.NetworkCost+osa1.NetworkCost, sa2.NetworkCost)
  177. }
  178. if !util.IsApproximately(sa1.LoadBalancerCost, osa2.LoadBalancerCost+osa1.LoadBalancerCost) {
  179. t.Fatalf("incorrect LoadBalancerCost: expected %.5f; actual %.5f", osa2.LoadBalancerCost+osa1.LoadBalancerCost, sa2.LoadBalancerCost)
  180. }
  181. if !util.IsApproximately(sa1.PVCost, osa2.PVCost+osa1.PVCost) {
  182. t.Fatalf("incorrect PVCost: expected %.5f; actual %.5f", osa2.PVCost+osa1.PVCost, sa2.PVCost)
  183. }
  184. if !util.IsApproximately(sa1.RAMCost, osa2.RAMCost+osa1.RAMCost) {
  185. t.Fatalf("incorrect RAMCost: expected %.5f; actual %.5f", osa2.RAMCost+osa1.RAMCost, sa2.RAMCost)
  186. }
  187. if !util.IsApproximately(sa1.SharedCost, osa2.SharedCost+osa1.SharedCost) {
  188. t.Fatalf("incorrect SharedCost: expected %.5f; actual %.5f", osa2.SharedCost+osa1.SharedCost, sa2.SharedCost)
  189. }
  190. if !util.IsApproximately(sa1.ExternalCost, osa2.ExternalCost+osa1.ExternalCost) {
  191. t.Fatalf("incorrect ExternalCost: expected %.5f; actual %.5f", osa2.ExternalCost+osa1.ExternalCost, sa2.ExternalCost)
  192. }
  193. })
  194. }
  195. func TestSummaryAllocation_Add_SanitizeNaNs(t *testing.T) {
  196. window, _ := ParseWindowUTC("yesterday")
  197. var sa, nansa *SummaryAllocation
  198. var err error
  199. start := *window.Start()
  200. end := *window.End()
  201. sa = &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: start,
  210. End: end,
  211. CPUCoreRequestAverage: 0.5,
  212. CPUCoreUsageAverage: 0.1,
  213. CPUCost: 0.2,
  214. GPUCost: 1.0,
  215. NetworkCost: 0.1,
  216. LoadBalancerCost: 0.6,
  217. PVCost: 0.005,
  218. RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
  219. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  220. RAMCost: 0.05,
  221. SharedCost: 1.0,
  222. ExternalCost: 1.0,
  223. }
  224. nansa = &SummaryAllocation{
  225. Name: "cluster1/namespace1/pod2/container2",
  226. Properties: &AllocationProperties{
  227. Cluster: "cluster1",
  228. Namespace: "namespace1",
  229. Pod: "pod2",
  230. Container: "container2",
  231. },
  232. Start: start,
  233. End: end,
  234. CPUCoreRequestAverage: math.NaN(),
  235. CPUCoreUsageAverage: math.NaN(),
  236. CPUCost: math.NaN(),
  237. GPUCost: math.NaN(),
  238. NetworkCost: math.NaN(),
  239. LoadBalancerCost: math.NaN(),
  240. PVCost: math.NaN(),
  241. RAMBytesRequestAverage: math.NaN(),
  242. RAMBytesUsageAverage: math.NaN(),
  243. RAMCost: math.NaN(),
  244. SharedCost: math.NaN(),
  245. ExternalCost: math.NaN(),
  246. }
  247. err = nansa.Add(sa)
  248. if err != nil {
  249. t.Fatalf("TestSummaryAllocation_Add_SanitizeNaNs: unexpected error: %s", err)
  250. }
  251. v := reflect.ValueOf(*nansa)
  252. checkAllFloat64sForNaN(t, v, "TestSummaryAllocation_Add_SanitizeNaNs")
  253. }
  254. func TestSummaryAllocationSet_RAMEfficiency(t *testing.T) {
  255. // Generating 6 sample summary allocations for testing
  256. var sa1, sa2, sa3, sa4, sa5, sa6, idlesa *SummaryAllocation
  257. // Generating accumulated summary allocation sets for testing
  258. var sas1, sas2, sas3, sas4, sas5, sas6 *SummaryAllocationSet
  259. window, _ := ParseWindowUTC("7d")
  260. saStart := *window.Start()
  261. saEnd := *window.End()
  262. sa1 = &SummaryAllocation{
  263. Name: "cluster1/namespace1/pod1/container1",
  264. Properties: &AllocationProperties{
  265. Cluster: "cluster1",
  266. Namespace: "namespace1",
  267. Pod: "pod1",
  268. Container: "container1",
  269. },
  270. Start: saStart,
  271. End: saEnd,
  272. RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
  273. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  274. RAMCost: 0.05,
  275. }
  276. sa2 = &SummaryAllocation{
  277. Name: "cluster1/namespace1/pod1/container2",
  278. Properties: &AllocationProperties{
  279. Cluster: "cluster1",
  280. Namespace: "namespace1",
  281. Pod: "pod1",
  282. Container: "container2",
  283. },
  284. Start: saStart,
  285. End: saEnd,
  286. RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
  287. RAMBytesUsageAverage: 15.0 * 1024.0 * 1024.0,
  288. RAMCost: 0.10,
  289. }
  290. sa3 = &SummaryAllocation{
  291. Name: "cluster1/namespace1/pod1/container3",
  292. Properties: &AllocationProperties{
  293. Cluster: "cluster1",
  294. Namespace: "namespace1",
  295. Pod: "pod1",
  296. Container: "container3",
  297. },
  298. Start: saStart,
  299. End: saEnd,
  300. RAMBytesRequestAverage: 0.0,
  301. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  302. RAMCost: 0.0,
  303. }
  304. sa4 = &SummaryAllocation{
  305. Name: "cluster1/namespace1/pod1/container4",
  306. Properties: &AllocationProperties{
  307. Cluster: "cluster1",
  308. Namespace: "namespace1",
  309. Pod: "pod1",
  310. Container: "container4",
  311. },
  312. Start: saStart,
  313. End: saEnd,
  314. RAMBytesRequestAverage: 0.0,
  315. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  316. RAMCost: 0.0,
  317. }
  318. sa5 = &SummaryAllocation{
  319. Name: "cluster1/namespace1/pod1/container4",
  320. Properties: &AllocationProperties{
  321. Cluster: "cluster1",
  322. Namespace: "namespace1",
  323. Pod: "pod1",
  324. Container: "container5",
  325. },
  326. Start: saStart,
  327. End: saEnd,
  328. RAMBytesRequestAverage: 0.0,
  329. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  330. RAMCost: 0.10,
  331. }
  332. sa6 = &SummaryAllocation{
  333. Name: "cluster1/namespace1/pod1/container4",
  334. Properties: &AllocationProperties{
  335. Cluster: "cluster1",
  336. Namespace: "namespace1",
  337. Pod: "pod1",
  338. Container: "container6",
  339. },
  340. Start: saStart,
  341. End: saEnd,
  342. RAMBytesRequestAverage: 0.0,
  343. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  344. RAMCost: 0.10,
  345. }
  346. idlesa = &SummaryAllocation{
  347. Name: IdleSuffix,
  348. Properties: &AllocationProperties{
  349. Cluster: "cluster1",
  350. Namespace: "namespace1",
  351. Pod: "pod1",
  352. Container: "container7",
  353. },
  354. Start: saStart,
  355. End: saEnd,
  356. CPUCost: 1.0,
  357. RAMCost: 1.0,
  358. }
  359. testcase1Map := map[string]*SummaryAllocation{
  360. "cluster1/namespace1/pod1/container1": sa1,
  361. "cluster1/namespace1/pod1/container2": sa2,
  362. }
  363. testcase2Map := map[string]*SummaryAllocation{
  364. "cluster1/namespace1/pod1/container3": sa3,
  365. "cluster1/namespace1/pod1/container4": sa4,
  366. }
  367. testcase3Map := map[string]*SummaryAllocation{
  368. "cluster1/namespace1/pod1/container5": sa5,
  369. "cluster1/namespace1/pod1/container6": sa6,
  370. }
  371. testcase4Map := map[string]*SummaryAllocation{}
  372. testcase5Map := map[string]*SummaryAllocation{
  373. "cluster1/namespace1/pod1/container1": sa1,
  374. "cluster1/namespace1/pod1/container2": sa2,
  375. "cluster1/namespace1/pod1/container3": sa3,
  376. "cluster1/namespace1/pod1/container4": sa4,
  377. "cluster1/namespace1/pod1/container5": sa5,
  378. "cluster1/namespace1/pod1/container6": sa6,
  379. }
  380. testcase6Map := map[string]*SummaryAllocation{
  381. "cluster1/namespace1/pod1/container1": sa1,
  382. "cluster1/namespace1/pod1/container2": sa2,
  383. "cluster1/__idle__": idlesa,
  384. }
  385. sas1 = &SummaryAllocationSet{
  386. SummaryAllocations: testcase1Map,
  387. Window: window,
  388. }
  389. sas2 = &SummaryAllocationSet{
  390. SummaryAllocations: testcase2Map,
  391. Window: window,
  392. }
  393. sas3 = &SummaryAllocationSet{
  394. SummaryAllocations: testcase3Map,
  395. Window: window,
  396. }
  397. sas4 = &SummaryAllocationSet{
  398. SummaryAllocations: testcase4Map,
  399. Window: window,
  400. }
  401. sas5 = &SummaryAllocationSet{
  402. SummaryAllocations: testcase5Map,
  403. Window: window,
  404. }
  405. sas6 = &SummaryAllocationSet{
  406. SummaryAllocations: testcase6Map,
  407. Window: window,
  408. }
  409. cases := []struct {
  410. name string
  411. testsas *SummaryAllocationSet
  412. expectedEfficiency float64
  413. }{
  414. {
  415. name: "Check RAMEfficiency when totalRAMBytesRequest over allocation summary set is greater than 0",
  416. testsas: sas1,
  417. expectedEfficiency: 0.25,
  418. },
  419. {
  420. name: "Check RAMEfficiency when totalRAMBytesRequest is 0 and totalRAMCost or totalRAMBytesUsage equal to 0",
  421. testsas: sas2,
  422. expectedEfficiency: 0.0,
  423. },
  424. {
  425. name: "Check RAMEfficiency when totalRAMBytesRequest is 0 and totalRAMCost or totalRAMBytesUsage is not 0",
  426. testsas: sas3,
  427. expectedEfficiency: 1.0,
  428. },
  429. {
  430. name: "Check RAMEfficiency when allocation summary set is empty",
  431. testsas: sas4,
  432. expectedEfficiency: 0.0,
  433. },
  434. {
  435. name: "Check RAMEfficiency over combination of all allocation summaries",
  436. testsas: sas5,
  437. expectedEfficiency: 0.65,
  438. },
  439. {
  440. name: "Check RAMEfficiency in presence of an idle allocation",
  441. testsas: sas6,
  442. expectedEfficiency: 0.25,
  443. },
  444. }
  445. for _, c := range cases {
  446. t.Run(c.name, func(t *testing.T) {
  447. returnEfficiency := c.testsas.RAMEfficiency()
  448. if !util.IsApproximately(c.expectedEfficiency, returnEfficiency) {
  449. t.Errorf("Case %s failed: Expected RAM Efficiency %.2f but got RAM Efficiency of as %.2f", c.name, c.expectedEfficiency, returnEfficiency)
  450. t.Fail()
  451. }
  452. })
  453. }
  454. }
  455. func TestSummaryAllocationSet_CPUEfficiency(t *testing.T) {
  456. // Generating 6 sample summary allocations for testing
  457. var sa1, sa2, sa3, sa4, sa5, sa6, idlesa *SummaryAllocation
  458. // Generating accumulated summary allocation sets for testing
  459. var sas1, sas2, sas3, sas4, sas5, sas6 *SummaryAllocationSet
  460. window, _ := ParseWindowUTC("7d")
  461. saStart := *window.Start()
  462. saEnd := *window.End()
  463. sa1 = &SummaryAllocation{
  464. Name: "cluster1/namespace1/pod1/container1",
  465. Properties: &AllocationProperties{
  466. Cluster: "cluster1",
  467. Namespace: "namespace1",
  468. Pod: "pod1",
  469. Container: "container1",
  470. },
  471. Start: saStart,
  472. End: saEnd,
  473. CPUCoreRequestAverage: 0.5,
  474. CPUCoreUsageAverage: 0.1,
  475. CPUCost: 0.2,
  476. }
  477. sa2 = &SummaryAllocation{
  478. Name: "cluster1/namespace1/pod1/container2",
  479. Properties: &AllocationProperties{
  480. Cluster: "cluster1",
  481. Namespace: "namespace1",
  482. Pod: "pod1",
  483. Container: "container2",
  484. },
  485. Start: saStart,
  486. End: saEnd,
  487. CPUCoreRequestAverage: 0.5,
  488. CPUCoreUsageAverage: 0.2,
  489. CPUCost: 0.2,
  490. }
  491. sa3 = &SummaryAllocation{
  492. Name: "cluster1/namespace1/pod1/container3",
  493. Properties: &AllocationProperties{
  494. Cluster: "cluster1",
  495. Namespace: "namespace1",
  496. Pod: "pod1",
  497. Container: "container3",
  498. },
  499. Start: saStart,
  500. End: saEnd,
  501. CPUCoreRequestAverage: 0.0,
  502. CPUCoreUsageAverage: 0.0,
  503. CPUCost: 1.0,
  504. }
  505. sa4 = &SummaryAllocation{
  506. Name: "cluster1/namespace1/pod1/container4",
  507. Properties: &AllocationProperties{
  508. Cluster: "cluster1",
  509. Namespace: "namespace1",
  510. Pod: "pod1",
  511. Container: "container4",
  512. },
  513. Start: saStart,
  514. End: saEnd,
  515. CPUCoreRequestAverage: 0.0,
  516. CPUCoreUsageAverage: 0.0,
  517. CPUCost: 2.0,
  518. }
  519. sa5 = &SummaryAllocation{
  520. Name: "cluster1/namespace1/pod1/container4",
  521. Properties: &AllocationProperties{
  522. Cluster: "cluster1",
  523. Namespace: "namespace1",
  524. Pod: "pod1",
  525. Container: "container5",
  526. },
  527. Start: saStart,
  528. End: saEnd,
  529. CPUCoreRequestAverage: 0.0,
  530. CPUCoreUsageAverage: 0.1,
  531. CPUCost: 0.2,
  532. }
  533. sa6 = &SummaryAllocation{
  534. Name: "cluster1/namespace1/pod1/container4",
  535. Properties: &AllocationProperties{
  536. Cluster: "cluster1",
  537. Namespace: "namespace1",
  538. Pod: "pod1",
  539. Container: "container6",
  540. },
  541. Start: saStart,
  542. End: saEnd,
  543. CPUCoreRequestAverage: 0.0,
  544. CPUCoreUsageAverage: 0.1,
  545. CPUCost: 0.2,
  546. }
  547. idlesa = &SummaryAllocation{
  548. Name: IdleSuffix,
  549. Properties: &AllocationProperties{
  550. Cluster: "cluster1",
  551. Namespace: "namespace1",
  552. Pod: "pod1",
  553. Container: "container7",
  554. },
  555. Start: saStart,
  556. End: saEnd,
  557. CPUCost: 1.0,
  558. RAMCost: 1.0,
  559. }
  560. testcase1Map := map[string]*SummaryAllocation{
  561. "cluster1/namespace1/pod1/container1": sa1,
  562. "cluster1/namespace1/pod1/container2": sa2,
  563. }
  564. testcase2Map := map[string]*SummaryAllocation{
  565. "cluster1/namespace1/pod1/container3": sa3,
  566. "cluster1/namespace1/pod1/container4": sa4,
  567. }
  568. testcase3Map := map[string]*SummaryAllocation{
  569. "cluster1/namespace1/pod1/container5": sa5,
  570. "cluster1/namespace1/pod1/container6": sa6,
  571. }
  572. testcase4Map := map[string]*SummaryAllocation{}
  573. testcase5Map := map[string]*SummaryAllocation{
  574. "cluster1/namespace1/pod1/container1": sa1,
  575. "cluster1/namespace1/pod1/container2": sa2,
  576. "cluster1/namespace1/pod1/container3": sa3,
  577. "cluster1/namespace1/pod1/container4": sa4,
  578. "cluster1/namespace1/pod1/container5": sa5,
  579. "cluster1/namespace1/pod1/container6": sa6,
  580. }
  581. testcase6Map := map[string]*SummaryAllocation{
  582. "cluster1/namespace1/pod1/container1": sa1,
  583. "cluster1/namespace1/pod1/container2": sa2,
  584. "cluster1/__idle__": idlesa,
  585. }
  586. sas1 = &SummaryAllocationSet{
  587. SummaryAllocations: testcase1Map,
  588. Window: window,
  589. }
  590. sas2 = &SummaryAllocationSet{
  591. SummaryAllocations: testcase2Map,
  592. Window: window,
  593. }
  594. sas3 = &SummaryAllocationSet{
  595. SummaryAllocations: testcase3Map,
  596. Window: window,
  597. }
  598. sas4 = &SummaryAllocationSet{
  599. SummaryAllocations: testcase4Map,
  600. Window: window,
  601. }
  602. sas5 = &SummaryAllocationSet{
  603. SummaryAllocations: testcase5Map,
  604. Window: window,
  605. }
  606. sas6 = &SummaryAllocationSet{
  607. SummaryAllocations: testcase6Map,
  608. Window: window,
  609. }
  610. cases := []struct {
  611. name string
  612. testsas *SummaryAllocationSet
  613. expectedEfficiency float64
  614. }{
  615. {
  616. name: "Check CPUEfficiency when totalCPUCoreRequest is greater than 0 over allocation summary set",
  617. testsas: sas1,
  618. expectedEfficiency: 0.30,
  619. },
  620. {
  621. name: "Check CPUEfficiency when totalCPUCoreRequest is 0 and totalCPUCost or totalCPUCoreUsage equal to 0",
  622. testsas: sas2,
  623. expectedEfficiency: 0.0,
  624. },
  625. {
  626. name: "Check CPUEfficiency when totalCPUCoreRequest is 0 and totalCPUCost or totalCPUCoreUsage is not 0",
  627. testsas: sas3,
  628. expectedEfficiency: 1.0,
  629. },
  630. {
  631. name: "Check CPUEfficiency when allocation summary set is empty",
  632. testsas: sas4,
  633. expectedEfficiency: 0.0,
  634. },
  635. {
  636. name: "Check CPUEfficiency over combination of all allocation summaries",
  637. testsas: sas5,
  638. expectedEfficiency: 0.50,
  639. },
  640. {
  641. name: "Check CPUEfficiency in presence of an idle allocation",
  642. testsas: sas6,
  643. expectedEfficiency: 0.30,
  644. },
  645. }
  646. for _, c := range cases {
  647. t.Run(c.name, func(t *testing.T) {
  648. returnEfficiency := c.testsas.CPUEfficiency()
  649. if !util.IsApproximately(c.expectedEfficiency, returnEfficiency) {
  650. t.Errorf("Case %s failed: Expected CPU Efficiency %.2f but got CPU Efficiency of as %.2f", c.name, c.expectedEfficiency, returnEfficiency)
  651. t.Fail()
  652. }
  653. })
  654. }
  655. }
  656. func TestSummaryAllocationSet_TotalEfficiency(t *testing.T) {
  657. // Generating 6 sample summary allocations for testing
  658. var sa1, sa2, sa3, sa4, sa5, sa6, idlesa *SummaryAllocation
  659. // Generating accumulated summary allocation sets for testing
  660. var sas1, sas2, sas3, sas4 *SummaryAllocationSet
  661. window, _ := ParseWindowUTC("7d")
  662. saStart := *window.Start()
  663. saEnd := *window.End()
  664. sa1 = &SummaryAllocation{
  665. Name: "cluster1/namespace1/pod1/container1",
  666. Properties: &AllocationProperties{
  667. Cluster: "cluster1",
  668. Namespace: "namespace1",
  669. Pod: "pod1",
  670. Container: "container1",
  671. },
  672. Start: saStart,
  673. End: saEnd,
  674. CPUCoreRequestAverage: 0.5,
  675. CPUCoreUsageAverage: 0.1,
  676. CPUCost: 0.0,
  677. RAMBytesRequestAverage: 0.0,
  678. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  679. RAMCost: 0.0,
  680. }
  681. sa2 = &SummaryAllocation{
  682. Name: "cluster1/namespace1/pod1/container2",
  683. Properties: &AllocationProperties{
  684. Cluster: "cluster1",
  685. Namespace: "namespace1",
  686. Pod: "pod1",
  687. Container: "container2",
  688. },
  689. Start: saStart,
  690. End: saEnd,
  691. CPUCoreRequestAverage: 0.5,
  692. CPUCoreUsageAverage: 0.2,
  693. CPUCost: 0.0,
  694. RAMBytesRequestAverage: 0.0,
  695. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  696. RAMCost: 0.0,
  697. }
  698. sa3 = &SummaryAllocation{
  699. Name: "cluster1/namespace1/pod1/container3",
  700. Properties: &AllocationProperties{
  701. Cluster: "cluster1",
  702. Namespace: "namespace1",
  703. Pod: "pod1",
  704. Container: "container3",
  705. },
  706. Start: saStart,
  707. End: saEnd,
  708. CPUCoreRequestAverage: 0.5,
  709. CPUCoreUsageAverage: 0.2,
  710. CPUCost: 1.0,
  711. RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
  712. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  713. RAMCost: 1.0,
  714. }
  715. sa4 = &SummaryAllocation{
  716. Name: "cluster1/namespace1/pod1/container4",
  717. Properties: &AllocationProperties{
  718. Cluster: "cluster1",
  719. Namespace: "namespace1",
  720. Pod: "pod1",
  721. Container: "container4",
  722. },
  723. Start: saStart,
  724. End: saEnd,
  725. CPUCoreRequestAverage: 0.5,
  726. CPUCoreUsageAverage: 0.1,
  727. CPUCost: 1.0,
  728. RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
  729. RAMBytesUsageAverage: 20.0 * 1024.0 * 1024.0,
  730. RAMCost: 1.0,
  731. }
  732. sa5 = &SummaryAllocation{
  733. Name: "cluster1/namespace1/pod1/container4",
  734. Properties: &AllocationProperties{
  735. Cluster: "cluster1",
  736. Namespace: "namespace1",
  737. Pod: "pod1",
  738. Container: "container5",
  739. },
  740. Start: saStart,
  741. End: saEnd,
  742. CPUCoreRequestAverage: 0.5,
  743. CPUCoreUsageAverage: 0.1,
  744. CPUCost: 1.0,
  745. RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
  746. RAMBytesUsageAverage: 10.0 * 1024.0 * 1024.0,
  747. RAMCost: 1.0,
  748. }
  749. sa6 = &SummaryAllocation{
  750. Name: "cluster1/namespace1/pod1/container4",
  751. Properties: &AllocationProperties{
  752. Cluster: "cluster1",
  753. Namespace: "namespace1",
  754. Pod: "pod1",
  755. Container: "container6",
  756. },
  757. Start: saStart,
  758. End: saEnd,
  759. CPUCoreRequestAverage: 0.5,
  760. CPUCoreUsageAverage: 0.2,
  761. CPUCost: 1.0,
  762. RAMBytesRequestAverage: 50.0 * 1024.0 * 1024.0,
  763. RAMBytesUsageAverage: 20.0 * 1024.0 * 1024.0,
  764. RAMCost: 1.0,
  765. }
  766. idlesa = &SummaryAllocation{
  767. Name: IdleSuffix,
  768. Properties: &AllocationProperties{
  769. Cluster: "cluster1",
  770. Namespace: "namespace1",
  771. Pod: "pod1",
  772. Container: "container7",
  773. },
  774. Start: saStart,
  775. End: saEnd,
  776. CPUCost: 1.0,
  777. RAMCost: 1.0,
  778. }
  779. testcase1Map := map[string]*SummaryAllocation{
  780. "cluster1/namespace1/pod1/container1": sa1,
  781. "cluster1/namespace1/pod1/container2": sa2,
  782. }
  783. testcase2Map := map[string]*SummaryAllocation{}
  784. testcase3Map := map[string]*SummaryAllocation{
  785. "cluster1/namespace1/pod1/container3": sa3,
  786. "cluster1/namespace1/pod1/container4": sa4,
  787. "cluster1/namespace1/pod1/container5": sa5,
  788. "cluster1/namespace1/pod1/container6": sa6,
  789. }
  790. testcase4Map := map[string]*SummaryAllocation{
  791. "cluster1/namespace1/pod1/container5": sa5,
  792. "cluster1/namespace1/pod1/container6": sa6,
  793. "cluster1/__idle__": idlesa,
  794. }
  795. sas1 = &SummaryAllocationSet{
  796. SummaryAllocations: testcase1Map,
  797. Window: window,
  798. }
  799. sas2 = &SummaryAllocationSet{
  800. SummaryAllocations: testcase2Map,
  801. Window: window,
  802. }
  803. sas3 = &SummaryAllocationSet{
  804. SummaryAllocations: testcase3Map,
  805. Window: window,
  806. }
  807. sas4 = &SummaryAllocationSet{
  808. SummaryAllocations: testcase4Map,
  809. Window: window,
  810. }
  811. cases := []struct {
  812. name string
  813. testsas *SummaryAllocationSet
  814. expectedEfficiency float64
  815. }{
  816. {
  817. name: "When TotalEfficiency when sum of TotalRAMCost and TotalCPUCost is 0",
  818. testsas: sas1,
  819. expectedEfficiency: 0.0,
  820. },
  821. {
  822. name: "Check TotalEfficiency when allocation summary set is empty",
  823. testsas: sas2,
  824. expectedEfficiency: 0.0,
  825. },
  826. {
  827. name: "Check TotalEfficiency over all 4 allocation summaries",
  828. testsas: sas3,
  829. expectedEfficiency: 0.30,
  830. },
  831. {
  832. name: "Check TotalEfficiency with idle cost",
  833. testsas: sas4,
  834. expectedEfficiency: 0.30,
  835. },
  836. }
  837. for _, c := range cases {
  838. t.Run(c.name, func(t *testing.T) {
  839. returnEfficiency := c.testsas.TotalEfficiency()
  840. if !util.IsApproximately(c.expectedEfficiency, returnEfficiency) {
  841. t.Errorf("Case %s failed: Expected Total Efficiency %.2f but got Total Efficiency of as %.2f", c.name, c.expectedEfficiency, returnEfficiency)
  842. t.Fail()
  843. }
  844. })
  845. }
  846. }
  847. func TestSummaryAllocationSetRange_AccumulateBy_None(t *testing.T) {
  848. ago4d := time.Now().UTC().Truncate(day).Add(-4 * day)
  849. ago3d := time.Now().UTC().Truncate(day).Add(-3 * day)
  850. ago2d := time.Now().UTC().Truncate(day).Add(-2 * day)
  851. yesterday := time.Now().UTC().Truncate(day).Add(-day)
  852. today := time.Now().UTC().Truncate(day)
  853. ago4dSAS := NewMockUnitSummaryAllocationSet(ago4d, day)
  854. ago4dSAS.Insert(NewMockUnitSummaryAllocation("4", ago4d, day, nil))
  855. ago3dSAS := NewMockUnitSummaryAllocationSet(ago3d, day)
  856. ago3dSAS.Insert(NewMockUnitSummaryAllocation("a", ago3d, day, nil))
  857. ago2dSAS := NewMockUnitSummaryAllocationSet(ago2d, day)
  858. ago2dSAS.Insert(NewMockUnitSummaryAllocation("", ago2d, day, nil))
  859. yesterdaySAS := NewMockUnitSummaryAllocationSet(yesterday, day)
  860. yesterdaySAS.Insert(NewMockUnitSummaryAllocation("", yesterday, day, nil))
  861. todaySAS := NewMockUnitSummaryAllocationSet(today, day)
  862. todaySAS.Insert(NewMockUnitSummaryAllocation("", today, day, nil))
  863. asr := NewSummaryAllocationSetRange(ago4dSAS, ago3dSAS, ago2dSAS, yesterdaySAS, todaySAS)
  864. asr, err := asr.Accumulate(AccumulateOptionNone)
  865. if err != nil {
  866. t.Fatalf("unexpected error calling accumulateBy: %s", err)
  867. }
  868. if len(asr.SummaryAllocationSets) != 5 {
  869. t.Fatalf("expected 5 allocation sets, got:%d", len(asr.SummaryAllocationSets))
  870. }
  871. }
  872. func TestSummaryAllocationSetRange_AccumulateBy_All(t *testing.T) {
  873. ago4d := time.Now().UTC().Truncate(day).Add(-4 * day)
  874. ago3d := time.Now().UTC().Truncate(day).Add(-3 * day)
  875. ago2d := time.Now().UTC().Truncate(day).Add(-2 * day)
  876. yesterday := time.Now().UTC().Truncate(day).Add(-day)
  877. today := time.Now().UTC().Truncate(day)
  878. ago4dSAS := NewMockUnitSummaryAllocationSet(ago4d, day)
  879. ago4dSAS.Insert(NewMockUnitSummaryAllocation("4", ago4d, day, nil))
  880. ago3dSAS := NewMockUnitSummaryAllocationSet(ago3d, day)
  881. ago3dSAS.Insert(NewMockUnitSummaryAllocation("a", ago3d, day, nil))
  882. ago2dSAS := NewMockUnitSummaryAllocationSet(ago2d, day)
  883. ago2dSAS.Insert(NewMockUnitSummaryAllocation("", ago2d, day, nil))
  884. yesterdaySAS := NewMockUnitSummaryAllocationSet(yesterday, day)
  885. yesterdaySAS.Insert(NewMockUnitSummaryAllocation("", yesterday, day, nil))
  886. todaySAS := NewMockUnitSummaryAllocationSet(today, day)
  887. todaySAS.Insert(NewMockUnitSummaryAllocation("", today, day, nil))
  888. asr := NewSummaryAllocationSetRange(ago4dSAS, ago3dSAS, ago2dSAS, yesterdaySAS, todaySAS)
  889. asr, err := asr.Accumulate(AccumulateOptionAll)
  890. if err != nil {
  891. t.Fatalf("unexpected error calling accumulateBy: %s", err)
  892. }
  893. if len(asr.SummaryAllocationSets) != 1 {
  894. t.Fatalf("expected 1 allocation set, got:%d", len(asr.SummaryAllocationSets))
  895. }
  896. allocMap := asr.SummaryAllocationSets[0].SummaryAllocations
  897. alloc := allocMap["cluster1/namespace1/pod1/container1"]
  898. if alloc.Minutes() != 4320.0 {
  899. t.Errorf("accumulating AllocationSetRange: expected %f minutes; actual %f", 4320.0, alloc.Minutes())
  900. }
  901. }
  902. func TestSummaryAllocationSetRange_AccumulateBy_Hour(t *testing.T) {
  903. ago4h := time.Now().UTC().Truncate(time.Hour).Add(-4 * time.Hour)
  904. ago3h := time.Now().UTC().Truncate(time.Hour).Add(-3 * time.Hour)
  905. ago2h := time.Now().UTC().Truncate(time.Hour).Add(-2 * time.Hour)
  906. ago1h := time.Now().UTC().Truncate(time.Hour).Add(-time.Hour)
  907. currentHour := time.Now().UTC().Truncate(time.Hour)
  908. ago4hAS := NewMockUnitSummaryAllocationSet(ago4h, time.Hour)
  909. ago4hAS.Insert(NewMockUnitSummaryAllocation("4", ago4h, time.Hour, nil))
  910. ago3hAS := NewMockUnitSummaryAllocationSet(ago3h, time.Hour)
  911. ago3hAS.Insert(NewMockUnitSummaryAllocation("a", ago3h, time.Hour, nil))
  912. ago2hAS := NewMockUnitSummaryAllocationSet(ago2h, time.Hour)
  913. ago2hAS.Insert(NewMockUnitSummaryAllocation("", ago2h, time.Hour, nil))
  914. ago1hAS := NewMockUnitSummaryAllocationSet(ago1h, time.Hour)
  915. ago1hAS.Insert(NewMockUnitSummaryAllocation("", ago1h, time.Hour, nil))
  916. currentHourAS := NewMockUnitSummaryAllocationSet(currentHour, time.Hour)
  917. currentHourAS.Insert(NewMockUnitSummaryAllocation("", currentHour, time.Hour, nil))
  918. asr := NewSummaryAllocationSetRange(ago4hAS, ago3hAS, ago2hAS, ago1hAS, currentHourAS)
  919. asr, err := asr.Accumulate(AccumulateOptionHour)
  920. if err != nil {
  921. t.Fatalf("unexpected error calling accumulateBy: %s", err)
  922. }
  923. if len(asr.SummaryAllocationSets) != 5 {
  924. t.Fatalf("expected 5 allocation sets, got:%d", len(asr.SummaryAllocationSets))
  925. }
  926. allocMap := asr.SummaryAllocationSets[0].SummaryAllocations
  927. alloc := allocMap["4"]
  928. if alloc.Minutes() != 60.0 {
  929. t.Errorf("accumulating AllocationSetRange: expected %f minutes; actual %f", 60.0, alloc.Minutes())
  930. }
  931. }
  932. func TestSummaryAllocationSetRange_AccumulateBy_Day_From_Day(t *testing.T) {
  933. ago4d := time.Now().UTC().Truncate(day).Add(-4 * day)
  934. ago3d := time.Now().UTC().Truncate(day).Add(-3 * day)
  935. ago2d := time.Now().UTC().Truncate(day).Add(-2 * day)
  936. yesterday := time.Now().UTC().Truncate(day).Add(-day)
  937. today := time.Now().UTC().Truncate(day)
  938. ago4dSAS := NewMockUnitSummaryAllocationSet(ago4d, day)
  939. ago4dSAS.Insert(NewMockUnitSummaryAllocation("4", ago4d, day, nil))
  940. ago3dSAS := NewMockUnitSummaryAllocationSet(ago3d, day)
  941. ago3dSAS.Insert(NewMockUnitSummaryAllocation("a", ago3d, day, nil))
  942. ago2dSAS := NewMockUnitSummaryAllocationSet(ago2d, day)
  943. ago2dSAS.Insert(NewMockUnitSummaryAllocation("", ago2d, day, nil))
  944. yesterdaySAS := NewMockUnitSummaryAllocationSet(yesterday, day)
  945. yesterdaySAS.Insert(NewMockUnitSummaryAllocation("", yesterday, day, nil))
  946. todaySAS := NewMockUnitSummaryAllocationSet(today, day)
  947. todaySAS.Insert(NewMockUnitSummaryAllocation("", today, day, nil))
  948. asr := NewSummaryAllocationSetRange(ago4dSAS, ago3dSAS, ago2dSAS, yesterdaySAS, todaySAS)
  949. asr, err := asr.Accumulate(AccumulateOptionNone)
  950. if err != nil {
  951. t.Fatalf("unexpected error calling accumulateBy: %s", err)
  952. }
  953. if len(asr.SummaryAllocationSets) != 5 {
  954. t.Fatalf("expected 5 allocation sets, got:%d", len(asr.SummaryAllocationSets))
  955. }
  956. allocMap := asr.SummaryAllocationSets[0].SummaryAllocations
  957. alloc := allocMap["4"]
  958. if alloc.Minutes() != 1440.0 {
  959. t.Errorf("accumulating AllocationSetRange: expected %f minutes; actual %f", 1440.0, alloc.Minutes())
  960. }
  961. }
  962. func TestSummaryAllocationSetRange_AccumulateBy_Day_From_Hours(t *testing.T) {
  963. ago4h := time.Now().UTC().Truncate(time.Hour).Add(-4 * time.Hour)
  964. ago3h := time.Now().UTC().Truncate(time.Hour).Add(-3 * time.Hour)
  965. ago2h := time.Now().UTC().Truncate(time.Hour).Add(-2 * time.Hour)
  966. ago1h := time.Now().UTC().Truncate(time.Hour).Add(-time.Hour)
  967. currentHour := time.Now().UTC().Truncate(time.Hour)
  968. ago4hAS := NewMockUnitSummaryAllocationSet(ago4h, time.Hour)
  969. ago4hAS.Insert(NewMockUnitSummaryAllocation("", ago4h, time.Hour, nil))
  970. ago3hAS := NewMockUnitSummaryAllocationSet(ago3h, time.Hour)
  971. ago3hAS.Insert(NewMockUnitSummaryAllocation("", ago3h, time.Hour, nil))
  972. ago2hAS := NewMockUnitSummaryAllocationSet(ago2h, time.Hour)
  973. ago2hAS.Insert(NewMockUnitSummaryAllocation("", ago2h, time.Hour, nil))
  974. ago1hAS := NewMockUnitSummaryAllocationSet(ago1h, time.Hour)
  975. ago1hAS.Insert(NewMockUnitSummaryAllocation("", ago1h, time.Hour, nil))
  976. currentHourAS := NewMockUnitSummaryAllocationSet(currentHour, time.Hour)
  977. currentHourAS.Insert(NewMockUnitSummaryAllocation("", currentHour, time.Hour, nil))
  978. asr := NewSummaryAllocationSetRange(ago4hAS, ago3hAS, ago2hAS, ago1hAS, currentHourAS)
  979. asr, err := asr.Accumulate(AccumulateOptionDay)
  980. if err != nil {
  981. t.Fatalf("unexpected error calling accumulateBy: %s", err)
  982. }
  983. if len(asr.SummaryAllocationSets) != 1 && len(asr.SummaryAllocationSets) != 2 {
  984. t.Fatalf("expected 1 allocation set, got:%d", len(asr.SummaryAllocationSets))
  985. }
  986. allocMap := asr.SummaryAllocationSets[0].SummaryAllocations
  987. alloc := allocMap["cluster1/namespace1/pod1/container1"]
  988. if alloc.Minutes() > 300.0 {
  989. t.Errorf("accumulating AllocationSetRange: expected %f or less minutes; actual %f", 300.0, alloc.Minutes())
  990. }
  991. }
  992. func TestSummaryAllocationSetRange_AccumulateBy_Week(t *testing.T) {
  993. ago9d := time.Now().UTC().Truncate(day).Add(-9 * day)
  994. ago8d := time.Now().UTC().Truncate(day).Add(-8 * day)
  995. ago7d := time.Now().UTC().Truncate(day).Add(-7 * day)
  996. ago6d := time.Now().UTC().Truncate(day).Add(-6 * day)
  997. ago5d := time.Now().UTC().Truncate(day).Add(-5 * day)
  998. ago4d := time.Now().UTC().Truncate(day).Add(-4 * day)
  999. ago3d := time.Now().UTC().Truncate(day).Add(-3 * day)
  1000. ago2d := time.Now().UTC().Truncate(day).Add(-2 * day)
  1001. yesterday := time.Now().UTC().Truncate(day).Add(-day)
  1002. today := time.Now().UTC().Truncate(day)
  1003. ago9dAS := NewMockUnitSummaryAllocationSet(ago9d, day)
  1004. ago9dAS.Insert(NewMockUnitSummaryAllocation("4", ago9d, day, nil))
  1005. ago8dAS := NewMockUnitSummaryAllocationSet(ago8d, day)
  1006. ago8dAS.Insert(NewMockUnitSummaryAllocation("4", ago8d, day, nil))
  1007. ago7dAS := NewMockUnitSummaryAllocationSet(ago7d, day)
  1008. ago7dAS.Insert(NewMockUnitSummaryAllocation("4", ago7d, day, nil))
  1009. ago6dAS := NewMockUnitSummaryAllocationSet(ago6d, day)
  1010. ago6dAS.Insert(NewMockUnitSummaryAllocation("4", ago6d, day, nil))
  1011. ago5dAS := NewMockUnitSummaryAllocationSet(ago5d, day)
  1012. ago5dAS.Insert(NewMockUnitSummaryAllocation("4", ago5d, day, nil))
  1013. ago4dAS := NewMockUnitSummaryAllocationSet(ago4d, day)
  1014. ago4dAS.Insert(NewMockUnitSummaryAllocation("4", ago4d, day, nil))
  1015. ago3dAS := NewMockUnitSummaryAllocationSet(ago3d, day)
  1016. ago3dAS.Insert(NewMockUnitSummaryAllocation("4", ago3d, day, nil))
  1017. ago2dAS := NewMockUnitSummaryAllocationSet(ago2d, day)
  1018. ago2dAS.Insert(NewMockUnitSummaryAllocation("4", ago2d, day, nil))
  1019. yesterdayAS := NewMockUnitSummaryAllocationSet(yesterday, day)
  1020. yesterdayAS.Insert(NewMockUnitSummaryAllocation("", yesterday, day, nil))
  1021. todayAS := NewMockUnitSummaryAllocationSet(today, day)
  1022. todayAS.Insert(NewMockUnitSummaryAllocation("4", today, day, nil))
  1023. asr := NewSummaryAllocationSetRange(ago9dAS, ago8dAS, ago7dAS, ago6dAS, ago5dAS, ago4dAS, ago3dAS, ago2dAS, yesterdayAS, todayAS)
  1024. asr, err := asr.Accumulate(AccumulateOptionWeek)
  1025. if err != nil {
  1026. t.Fatalf("unexpected error calling accumulateBy: %s", err)
  1027. }
  1028. if len(asr.SummaryAllocationSets) != 2 && len(asr.SummaryAllocationSets) != 3 {
  1029. t.Fatalf("expected 2 allocation sets, got:%d", len(asr.SummaryAllocationSets))
  1030. }
  1031. for _, as := range asr.SummaryAllocationSets {
  1032. if as.Window.Duration() < time.Hour*24 || as.Window.Duration() > time.Hour*24*7 {
  1033. t.Fatalf("expected window duration to be between 1 and 7 days, got:%s", as.Window.Duration().String())
  1034. }
  1035. }
  1036. }
  1037. func TestSummaryAllocationSetRange_AccumulateBy_Month(t *testing.T) {
  1038. prevMonth1stDay := time.Date(2020, 01, 29, 0, 0, 0, 0, time.UTC)
  1039. prevMonth2ndDay := time.Date(2020, 01, 30, 0, 0, 0, 0, time.UTC)
  1040. prevMonth3ndDay := time.Date(2020, 01, 31, 0, 0, 0, 0, time.UTC)
  1041. nextMonth1stDay := time.Date(2020, 02, 01, 0, 0, 0, 0, time.UTC)
  1042. prev1AS := NewMockUnitSummaryAllocationSet(prevMonth1stDay, day)
  1043. prev1AS.Insert(NewMockUnitSummaryAllocation("", prevMonth1stDay, day, nil))
  1044. prev2AS := NewMockUnitSummaryAllocationSet(prevMonth2ndDay, day)
  1045. prev2AS.Insert(NewMockUnitSummaryAllocation("", prevMonth2ndDay, day, nil))
  1046. prev3AS := NewMockUnitSummaryAllocationSet(prevMonth3ndDay, day)
  1047. prev3AS.Insert(NewMockUnitSummaryAllocation("", prevMonth3ndDay, day, nil))
  1048. nextAS := NewMockUnitSummaryAllocationSet(nextMonth1stDay, day)
  1049. nextAS.Insert(NewMockUnitSummaryAllocation("", nextMonth1stDay, day, nil))
  1050. asr := NewSummaryAllocationSetRange(prev1AS, prev2AS, prev3AS, nextAS)
  1051. asr, err := asr.Accumulate(AccumulateOptionMonth)
  1052. if err != nil {
  1053. t.Fatalf("unexpected error calling accumulateBy: %s", err)
  1054. }
  1055. if len(asr.SummaryAllocationSets) != 2 {
  1056. t.Fatalf("expected 2 allocation sets, got:%d", len(asr.SummaryAllocationSets))
  1057. }
  1058. for _, as := range asr.SummaryAllocationSets {
  1059. if as.Window.Duration() < time.Hour*24 || as.Window.Duration() > time.Hour*24*31 {
  1060. t.Fatalf("expected window duration to be between 1 and 7 days, got:%s", as.Window.Duration().String())
  1061. }
  1062. }
  1063. }