price_test.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. package pricing
  2. import (
  3. "errors"
  4. "testing"
  5. "github.com/opencost/opencost/core/pkg/unit"
  6. )
  7. func TestGetPrices(t *testing.T) {
  8. testCases := []struct {
  9. name string
  10. prices Prices
  11. }{
  12. {
  13. name: "empty Prices",
  14. prices: Prices{},
  15. },
  16. {
  17. name: "single hourly price",
  18. prices: Prices{
  19. unit.USD: []Price{
  20. {
  21. Currency: unit.USD,
  22. Unit: unit.Hour,
  23. Price: 0.096,
  24. },
  25. },
  26. },
  27. },
  28. {
  29. name: "single set of per-resource prices",
  30. prices: Prices{
  31. unit.USD: []Price{
  32. {
  33. Currency: unit.USD,
  34. Unit: unit.VCPUHour,
  35. Price: 0.031611,
  36. },
  37. {
  38. Currency: unit.USD,
  39. Unit: unit.RAMGiBHour,
  40. Price: 0.004237,
  41. },
  42. },
  43. },
  44. },
  45. {
  46. name: "prices for multiple currencies",
  47. prices: Prices{
  48. unit.USD: []Price{
  49. {
  50. Currency: unit.USD,
  51. Unit: unit.VCPUHour,
  52. Price: 0.031611,
  53. },
  54. {
  55. Currency: unit.USD,
  56. Unit: unit.RAMGiBHour,
  57. Price: 0.004237,
  58. },
  59. },
  60. unit.CNY: []Price{
  61. {
  62. Currency: unit.CNY,
  63. Unit: unit.VCPUHour,
  64. Price: 3.1611,
  65. },
  66. {
  67. Currency: unit.CNY,
  68. Unit: unit.RAMGiBHour,
  69. Price: 0.4237,
  70. },
  71. },
  72. },
  73. },
  74. }
  75. for _, tt := range testCases {
  76. t.Run(tt.name, func(t *testing.T) {
  77. result := tt.prices.GetPrices()
  78. expectedLen := 0
  79. for _, prices := range tt.prices {
  80. expectedLen += len(prices)
  81. }
  82. if len(result) != expectedLen {
  83. t.Errorf("expected %d prices, got %d", expectedLen, len(result))
  84. }
  85. })
  86. }
  87. }
  88. func TestGetPricesInCurrency(t *testing.T) {
  89. tests := []struct {
  90. name string
  91. prices Prices
  92. currency unit.Currency
  93. expectedCount int
  94. expectError bool
  95. errorType error
  96. }{
  97. {
  98. name: "empty Prices - should return NotFound error",
  99. prices: Prices{},
  100. currency: unit.USD,
  101. expectedCount: 0,
  102. expectError: true,
  103. errorType: NotFound,
  104. },
  105. {
  106. name: "currency not found - should return NotFound error",
  107. prices: Prices{
  108. unit.EUR: []Price{
  109. {
  110. Currency: unit.EUR,
  111. Unit: unit.VCPUHour,
  112. Price: 0.028,
  113. },
  114. },
  115. },
  116. currency: unit.USD,
  117. expectedCount: 0,
  118. expectError: true,
  119. errorType: NotFound,
  120. },
  121. {
  122. name: "single matching currency",
  123. prices: Prices{
  124. unit.USD: []Price{
  125. {
  126. Currency: unit.USD,
  127. Unit: unit.VCPUHour,
  128. Price: 0.031611,
  129. },
  130. },
  131. },
  132. currency: unit.USD,
  133. expectedCount: 1,
  134. expectError: false,
  135. },
  136. {
  137. name: "multiple currencies - find USD",
  138. prices: Prices{
  139. unit.USD: []Price{
  140. {
  141. Currency: unit.USD,
  142. Unit: unit.VCPUHour,
  143. Price: 0.031611,
  144. },
  145. },
  146. unit.EUR: []Price{
  147. {
  148. Currency: unit.EUR,
  149. Unit: unit.VCPUHour,
  150. Price: 0.028,
  151. },
  152. },
  153. unit.GBP: []Price{
  154. {
  155. Currency: unit.GBP,
  156. Unit: unit.RAMGiBHour,
  157. Price: 0.025,
  158. },
  159. },
  160. },
  161. currency: unit.USD,
  162. expectedCount: 1,
  163. expectError: false,
  164. },
  165. {
  166. name: "multiple currencies - find EUR",
  167. prices: Prices{
  168. unit.USD: []Price{
  169. {
  170. Currency: unit.USD,
  171. Unit: unit.VCPUHour,
  172. Price: 0.031611,
  173. },
  174. },
  175. unit.EUR: []Price{
  176. {
  177. Currency: unit.EUR,
  178. Unit: unit.VCPUHour,
  179. Price: 0.028,
  180. },
  181. },
  182. },
  183. currency: unit.EUR,
  184. expectedCount: 1,
  185. expectError: false,
  186. },
  187. }
  188. for _, tt := range tests {
  189. t.Run(tt.name, func(t *testing.T) {
  190. result, err := tt.prices.GetPricesInCurrency(tt.currency)
  191. if tt.expectError {
  192. if err == nil {
  193. t.Error("expected error but got none")
  194. }
  195. if !errors.Is(err, tt.errorType) {
  196. t.Errorf("expected error type %v, got %v", tt.errorType, err)
  197. }
  198. if len(result) != 0 {
  199. t.Errorf("expected nil or empty result on error, got %d prices", len(result))
  200. }
  201. } else {
  202. if err != nil {
  203. t.Errorf("unexpected error: %v", err)
  204. }
  205. if len(result) != tt.expectedCount {
  206. t.Errorf("expected %d prices, got %d", tt.expectedCount, len(result))
  207. }
  208. // Verify all returned prices have the requested currency
  209. for _, price := range result {
  210. if price.Currency != tt.currency {
  211. t.Errorf("expected currency %v, got %v", tt.currency, price.Currency)
  212. }
  213. }
  214. }
  215. })
  216. }
  217. }
  218. func TestGetPricesInCurrencyWithDefault(t *testing.T) {
  219. testCases := []struct {
  220. name string
  221. prices Prices
  222. currency unit.Currency
  223. defaultCurrency unit.Currency
  224. expectedCount int
  225. expectError bool
  226. expectedCurr unit.Currency
  227. }{
  228. {
  229. name: "empty Prices - should return NotFound error",
  230. prices: Prices{},
  231. currency: unit.USD,
  232. defaultCurrency: unit.EUR,
  233. expectedCount: 0,
  234. expectError: true,
  235. },
  236. {
  237. name: "currency found - should return requested currency",
  238. prices: Prices{
  239. unit.USD: []Price{
  240. {
  241. Currency: unit.USD,
  242. Unit: unit.VCPUHour,
  243. Price: 0.031611,
  244. },
  245. },
  246. },
  247. currency: unit.USD,
  248. defaultCurrency: unit.EUR,
  249. expectedCount: 1,
  250. expectError: false,
  251. expectedCurr: unit.USD,
  252. },
  253. {
  254. name: "currency not found - should fallback to default",
  255. prices: Prices{
  256. unit.EUR: []Price{
  257. {
  258. Currency: unit.EUR,
  259. Unit: unit.VCPUHour,
  260. Price: 0.028,
  261. },
  262. },
  263. },
  264. currency: unit.USD,
  265. defaultCurrency: unit.EUR,
  266. expectedCount: 1,
  267. expectError: false,
  268. expectedCurr: unit.EUR,
  269. },
  270. {
  271. name: "neither currency nor default found - should return NotFound error",
  272. prices: Prices{
  273. unit.GBP: []Price{
  274. {
  275. Currency: unit.GBP,
  276. Unit: unit.VCPUHour,
  277. Price: 0.025,
  278. },
  279. },
  280. },
  281. currency: unit.USD,
  282. defaultCurrency: unit.EUR,
  283. expectedCount: 0,
  284. expectError: true,
  285. },
  286. {
  287. name: "multiple currencies - prefer requested over default",
  288. prices: Prices{
  289. unit.USD: []Price{
  290. {
  291. Currency: unit.USD,
  292. Unit: unit.VCPUHour,
  293. Price: 0.031611,
  294. },
  295. },
  296. unit.EUR: []Price{
  297. {
  298. Currency: unit.EUR,
  299. Unit: unit.VCPUHour,
  300. Price: 0.028,
  301. },
  302. },
  303. },
  304. currency: unit.USD,
  305. defaultCurrency: unit.EUR,
  306. expectedCount: 1,
  307. expectError: false,
  308. expectedCurr: unit.USD,
  309. },
  310. {
  311. name: "same currency and default - should return requested",
  312. prices: Prices{
  313. unit.USD: []Price{
  314. {
  315. Currency: unit.USD,
  316. Unit: unit.VCPUHour,
  317. Price: 0.031611,
  318. },
  319. },
  320. },
  321. currency: unit.USD,
  322. defaultCurrency: unit.USD,
  323. expectedCount: 1,
  324. expectError: false,
  325. expectedCurr: unit.USD,
  326. },
  327. }
  328. for _, tt := range testCases {
  329. t.Run(tt.name, func(t *testing.T) {
  330. result, err := tt.prices.GetPricesInCurrencyWithDefault(tt.currency, tt.defaultCurrency)
  331. if tt.expectError {
  332. if err == nil {
  333. t.Error("expected error but got none")
  334. }
  335. if !errors.Is(err, NotFound) {
  336. t.Errorf("expected NotFound error, got %v", err)
  337. }
  338. } else {
  339. if err != nil {
  340. t.Errorf("unexpected error: %v", err)
  341. }
  342. if len(result) != tt.expectedCount {
  343. t.Errorf("expected %d prices, got %d", tt.expectedCount, len(result))
  344. }
  345. // Verify all returned prices have the expected currency
  346. for _, price := range result {
  347. if price.Currency != tt.expectedCurr {
  348. t.Errorf("expected currency %v, got %v", tt.expectedCurr, price.Currency)
  349. }
  350. }
  351. }
  352. })
  353. }
  354. }