memoryrepository_test.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. package cloudcost
  2. import (
  3. "reflect"
  4. "sort"
  5. "testing"
  6. "time"
  7. "github.com/opencost/opencost/core/pkg/opencost"
  8. "github.com/opencost/opencost/core/pkg/util/timeutil"
  9. )
  10. func TestMemoryRepository_Get(t *testing.T) {
  11. defaultStart := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
  12. defaultEnd := defaultStart.Add(timeutil.Day)
  13. defaultData := map[string]map[time.Time]*opencost.CloudCostSet{
  14. "key-1": {
  15. defaultStart: DefaultMockCloudCostSet(defaultStart, defaultEnd, "aws", "key-1"),
  16. },
  17. }
  18. tests := map[string]struct {
  19. data map[string]map[time.Time]*opencost.CloudCostSet
  20. startTime time.Time
  21. key string
  22. want *opencost.CloudCostSet
  23. wantErr bool
  24. }{
  25. "No Data": {
  26. data: map[string]map[time.Time]*opencost.CloudCostSet{},
  27. startTime: defaultStart,
  28. key: "key-1",
  29. want: nil,
  30. wantErr: false,
  31. },
  32. "has data": {
  33. data: defaultData,
  34. startTime: defaultStart,
  35. key: "key-1",
  36. want: DefaultMockCloudCostSet(defaultStart, defaultEnd, "aws", "key-1"),
  37. wantErr: false,
  38. },
  39. "wrong key": {
  40. data: defaultData,
  41. startTime: defaultStart,
  42. key: "key-2",
  43. want: nil,
  44. wantErr: false,
  45. },
  46. "wrong time": {
  47. data: defaultData,
  48. startTime: defaultEnd,
  49. key: "key-1",
  50. want: nil,
  51. wantErr: false,
  52. },
  53. }
  54. for name, tt := range tests {
  55. t.Run(name, func(t *testing.T) {
  56. m := &MemoryRepository{
  57. data: tt.data,
  58. }
  59. got, err := m.Get(tt.startTime, tt.key)
  60. if (err != nil) != tt.wantErr {
  61. t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr)
  62. return
  63. }
  64. if !reflect.DeepEqual(got, tt.want) {
  65. t.Errorf("Get() got = %v, want %v", got, tt.want)
  66. }
  67. })
  68. }
  69. }
  70. func TestMemoryRepository_Has(t *testing.T) {
  71. defaultStart := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
  72. defaultEnd := defaultStart.Add(timeutil.Day)
  73. defaultData := map[string]map[time.Time]*opencost.CloudCostSet{
  74. "key-1": {
  75. defaultStart: DefaultMockCloudCostSet(defaultStart, defaultEnd, "aws", "key-1"),
  76. },
  77. }
  78. tests := map[string]struct {
  79. data map[string]map[time.Time]*opencost.CloudCostSet
  80. startTime time.Time
  81. key string
  82. want bool
  83. wantErr bool
  84. }{
  85. "No Data": {
  86. data: map[string]map[time.Time]*opencost.CloudCostSet{},
  87. startTime: defaultStart,
  88. key: "key-1",
  89. want: false,
  90. wantErr: false,
  91. },
  92. "has data": {
  93. data: defaultData,
  94. startTime: defaultStart,
  95. key: "key-1",
  96. want: true,
  97. wantErr: false,
  98. },
  99. "wrong key": {
  100. data: defaultData,
  101. startTime: defaultStart,
  102. key: "key-2",
  103. want: false,
  104. wantErr: false,
  105. },
  106. "wrong time": {
  107. data: defaultData,
  108. startTime: defaultEnd,
  109. key: "key-1",
  110. want: false,
  111. wantErr: false,
  112. },
  113. }
  114. for name, tt := range tests {
  115. t.Run(name, func(t *testing.T) {
  116. m := &MemoryRepository{
  117. data: tt.data,
  118. }
  119. got, err := m.Has(tt.startTime, tt.key)
  120. if (err != nil) != tt.wantErr {
  121. t.Errorf("Has() error = %v, wantErr %v", err, tt.wantErr)
  122. return
  123. }
  124. if got != tt.want {
  125. t.Errorf("Has() got = %v, want %v", got, tt.want)
  126. }
  127. })
  128. }
  129. }
  130. func TestMemoryRepository_Keys(t *testing.T) {
  131. tests := map[string]struct {
  132. data map[string]map[time.Time]*opencost.CloudCostSet
  133. want []string
  134. wantErr bool
  135. }{
  136. "empty": {
  137. data: map[string]map[time.Time]*opencost.CloudCostSet{},
  138. want: []string{},
  139. wantErr: false,
  140. },
  141. "one-key": {
  142. data: map[string]map[time.Time]*opencost.CloudCostSet{
  143. "key-1": nil,
  144. },
  145. want: []string{"key-1"},
  146. wantErr: false,
  147. },
  148. "two-key": {
  149. data: map[string]map[time.Time]*opencost.CloudCostSet{
  150. "key-1": nil,
  151. "key-2": {
  152. time.Now(): nil,
  153. time.Now().Add(1): nil,
  154. },
  155. },
  156. want: []string{"key-1", "key-2"},
  157. wantErr: false,
  158. },
  159. }
  160. for name, tt := range tests {
  161. t.Run(name, func(t *testing.T) {
  162. m := &MemoryRepository{
  163. data: tt.data,
  164. }
  165. got, err := m.Keys()
  166. if (err != nil) != tt.wantErr {
  167. t.Errorf("Keys() error = %v, wantErr %v", err, tt.wantErr)
  168. return
  169. }
  170. sort.Strings(got)
  171. sort.Strings(tt.want)
  172. if !reflect.DeepEqual(got, tt.want) {
  173. t.Errorf("Keys() got = %v, want %v", got, tt.want)
  174. }
  175. })
  176. }
  177. }
  178. func TestMemoryRepository_Put(t *testing.T) {
  179. defaultStart := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
  180. defaultEnd := defaultStart.Add(timeutil.Day)
  181. tests := map[string]struct {
  182. data map[string]map[time.Time]*opencost.CloudCostSet
  183. input *opencost.CloudCostSet
  184. want map[string]map[time.Time]*opencost.CloudCostSet
  185. wantErr bool
  186. }{
  187. "nil set": {
  188. data: map[string]map[time.Time]*opencost.CloudCostSet{},
  189. input: nil,
  190. want: map[string]map[time.Time]*opencost.CloudCostSet{},
  191. wantErr: true,
  192. },
  193. "invalid window": {
  194. data: map[string]map[time.Time]*opencost.CloudCostSet{},
  195. input: &opencost.CloudCostSet{
  196. CloudCosts: nil,
  197. Window: opencost.Window{},
  198. Integration: "key-1",
  199. },
  200. want: map[string]map[time.Time]*opencost.CloudCostSet{},
  201. wantErr: true,
  202. },
  203. "invalid key": {
  204. data: map[string]map[time.Time]*opencost.CloudCostSet{},
  205. input: &opencost.CloudCostSet{
  206. CloudCosts: nil,
  207. Window: opencost.NewClosedWindow(defaultStart, defaultEnd),
  208. Integration: "",
  209. },
  210. want: map[string]map[time.Time]*opencost.CloudCostSet{},
  211. wantErr: true,
  212. },
  213. "valid input": {
  214. data: map[string]map[time.Time]*opencost.CloudCostSet{},
  215. input: DefaultMockCloudCostSet(defaultStart, defaultEnd, "aws", "key-1"),
  216. want: map[string]map[time.Time]*opencost.CloudCostSet{
  217. "key-1": {
  218. defaultStart: DefaultMockCloudCostSet(defaultStart, defaultEnd, "aws", "key-1"),
  219. },
  220. },
  221. wantErr: false,
  222. },
  223. "overwrite": {
  224. data: map[string]map[time.Time]*opencost.CloudCostSet{
  225. "key-1": {
  226. defaultStart: DefaultMockCloudCostSet(defaultStart, defaultEnd, "gcp", "key-1"),
  227. },
  228. },
  229. input: DefaultMockCloudCostSet(defaultStart, defaultEnd, "aws", "key-1"),
  230. want: map[string]map[time.Time]*opencost.CloudCostSet{
  231. "key-1": {
  232. defaultStart: DefaultMockCloudCostSet(defaultStart, defaultEnd, "aws", "key-1"),
  233. },
  234. },
  235. wantErr: false,
  236. },
  237. "invalid overwrite": {
  238. data: map[string]map[time.Time]*opencost.CloudCostSet{
  239. "key-1": {
  240. defaultStart: DefaultMockCloudCostSet(defaultStart, defaultEnd, "gcp", "key-1"),
  241. },
  242. },
  243. input: &opencost.CloudCostSet{
  244. Window: opencost.NewWindow(&defaultStart, nil),
  245. Integration: "key-1",
  246. },
  247. want: map[string]map[time.Time]*opencost.CloudCostSet{
  248. "key-1": {
  249. defaultStart: DefaultMockCloudCostSet(defaultStart, defaultEnd, "gcp", "key-1"),
  250. },
  251. },
  252. wantErr: true,
  253. },
  254. }
  255. for name, tt := range tests {
  256. t.Run(name, func(t *testing.T) {
  257. m := &MemoryRepository{data: tt.data}
  258. if err := m.Put(tt.input); (err != nil) != tt.wantErr {
  259. t.Errorf("Put() error = %v, wantErr %v", err, tt.wantErr)
  260. }
  261. if !reflect.DeepEqual(m.data, tt.want) {
  262. t.Errorf("Put() got = %v, want %v", m.data, tt.want)
  263. }
  264. })
  265. }
  266. }
  267. func TestMemoryRepository_Expire(t *testing.T) {
  268. dayOne := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
  269. dayTwo := time.Date(2023, 1, 2, 0, 0, 0, 0, time.UTC)
  270. dayThree := time.Date(2023, 1, 3, 0, 0, 0, 0, time.UTC)
  271. tests := map[string]struct {
  272. data map[string]map[time.Time]*opencost.CloudCostSet
  273. limit time.Time
  274. want map[string]map[time.Time]*opencost.CloudCostSet
  275. wantErr bool
  276. }{
  277. "no expire": {
  278. data: map[string]map[time.Time]*opencost.CloudCostSet{
  279. "key-1": {
  280. dayTwo: nil,
  281. },
  282. },
  283. limit: dayOne,
  284. want: map[string]map[time.Time]*opencost.CloudCostSet{
  285. "key-1": {
  286. dayTwo: nil,
  287. },
  288. },
  289. wantErr: false,
  290. },
  291. "limit match": {
  292. data: map[string]map[time.Time]*opencost.CloudCostSet{
  293. "key-1": {
  294. dayTwo: nil,
  295. },
  296. },
  297. limit: dayTwo,
  298. want: map[string]map[time.Time]*opencost.CloudCostSet{
  299. "key-1": {
  300. dayTwo: nil,
  301. },
  302. },
  303. wantErr: false,
  304. },
  305. "single expire": {
  306. data: map[string]map[time.Time]*opencost.CloudCostSet{
  307. "key-1": {
  308. dayTwo: nil,
  309. },
  310. },
  311. limit: dayThree,
  312. want: map[string]map[time.Time]*opencost.CloudCostSet{},
  313. wantErr: false,
  314. },
  315. "one key expire": {
  316. data: map[string]map[time.Time]*opencost.CloudCostSet{
  317. "key-1": {
  318. dayOne: nil,
  319. dayTwo: nil,
  320. },
  321. "key-2": {
  322. dayOne: nil,
  323. },
  324. },
  325. limit: dayTwo,
  326. want: map[string]map[time.Time]*opencost.CloudCostSet{
  327. "key-1": {
  328. dayTwo: nil,
  329. },
  330. },
  331. wantErr: false,
  332. },
  333. }
  334. for name, tt := range tests {
  335. t.Run(name, func(t *testing.T) {
  336. m := &MemoryRepository{
  337. data: tt.data,
  338. }
  339. if err := m.Expire(tt.limit); (err != nil) != tt.wantErr {
  340. t.Errorf("Expire() error = %v, wantErr %v", err, tt.wantErr)
  341. }
  342. if !reflect.DeepEqual(m.data, tt.want) {
  343. t.Errorf("Expire() got = %v, want %v", m.data, tt.want)
  344. }
  345. })
  346. }
  347. }