queryservice_helper_test.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. package cloudcost
  2. import (
  3. "reflect"
  4. "testing"
  5. "time"
  6. "github.com/opencost/opencost/core/pkg/filter/cloudcost"
  7. "github.com/opencost/opencost/core/pkg/opencost"
  8. "github.com/opencost/opencost/core/pkg/util/httputil"
  9. )
  10. func TestParseCloudCostRequest(t *testing.T) {
  11. windowStr := "2023-01-01T00:00:00Z,2023-01-02T00:00:00Z"
  12. start := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
  13. end := time.Date(2023, 1, 2, 0, 0, 0, 0, time.UTC)
  14. validFilterStr := `service:"AmazonEC2"`
  15. parser := cloudcost.NewCloudCostFilterParser()
  16. validFilter, _ := parser.Parse(validFilterStr)
  17. tests := map[string]struct {
  18. values map[string][]string
  19. want *QueryRequest
  20. wantErr bool
  21. }{
  22. "missing window": {
  23. values: map[string][]string{},
  24. want: nil,
  25. wantErr: true,
  26. },
  27. "invalid window": {
  28. values: map[string][]string{
  29. "window": {"invalid"},
  30. },
  31. want: nil,
  32. wantErr: true,
  33. },
  34. "valid window": {
  35. values: map[string][]string{
  36. "window": {windowStr},
  37. },
  38. want: &QueryRequest{
  39. Start: start,
  40. End: end,
  41. AggregateBy: []string{opencost.CloudCostInvoiceEntityIDProp, opencost.CloudCostAccountIDProp, opencost.CloudCostProviderProp, opencost.CloudCostProviderIDProp, opencost.CloudCostCategoryProp, opencost.CloudCostServiceProp},
  42. Accumulate: "",
  43. Filter: nil,
  44. },
  45. wantErr: false,
  46. },
  47. "valid aggregate": {
  48. values: map[string][]string{
  49. "window": {windowStr},
  50. "aggregate": {"invoiceEntityID,accountID,label:app"},
  51. },
  52. want: &QueryRequest{
  53. Start: start,
  54. End: end,
  55. AggregateBy: []string{opencost.CloudCostInvoiceEntityIDProp, opencost.CloudCostAccountIDProp, "label:app"},
  56. Accumulate: "",
  57. Filter: nil,
  58. },
  59. wantErr: false,
  60. },
  61. "invalid aggregate": {
  62. values: map[string][]string{
  63. "window": {windowStr},
  64. "aggregate": {"invalid"},
  65. },
  66. want: nil,
  67. wantErr: true,
  68. },
  69. "valid accumulate": {
  70. values: map[string][]string{
  71. "window": {windowStr},
  72. "accumulate": {"week"},
  73. },
  74. want: &QueryRequest{
  75. Start: start,
  76. End: end,
  77. AggregateBy: []string{opencost.CloudCostInvoiceEntityIDProp, opencost.CloudCostAccountIDProp, opencost.CloudCostProviderProp, opencost.CloudCostProviderIDProp, opencost.CloudCostCategoryProp, opencost.CloudCostServiceProp},
  78. Accumulate: opencost.AccumulateOptionWeek,
  79. Filter: nil,
  80. },
  81. wantErr: false,
  82. },
  83. "invalid accumulate": {
  84. values: map[string][]string{
  85. "window": {windowStr},
  86. "accumulate": {"invalid"},
  87. },
  88. want: &QueryRequest{
  89. Start: start,
  90. End: end,
  91. AggregateBy: []string{opencost.CloudCostInvoiceEntityIDProp, opencost.CloudCostAccountIDProp, opencost.CloudCostProviderProp, opencost.CloudCostProviderIDProp, opencost.CloudCostCategoryProp, opencost.CloudCostServiceProp},
  92. Accumulate: opencost.AccumulateOptionNone,
  93. Filter: nil,
  94. },
  95. wantErr: false,
  96. },
  97. "valid filter": {
  98. values: map[string][]string{
  99. "window": {windowStr},
  100. "filter": {validFilterStr},
  101. },
  102. want: &QueryRequest{
  103. Start: start,
  104. End: end,
  105. AggregateBy: []string{opencost.CloudCostInvoiceEntityIDProp, opencost.CloudCostAccountIDProp, opencost.CloudCostProviderProp, opencost.CloudCostProviderIDProp, opencost.CloudCostCategoryProp, opencost.CloudCostServiceProp},
  106. Accumulate: opencost.AccumulateOptionNone,
  107. Filter: validFilter,
  108. },
  109. wantErr: false,
  110. },
  111. "invalid filter": {
  112. values: map[string][]string{
  113. "window": {windowStr},
  114. "filter": {"invalid"},
  115. },
  116. want: nil,
  117. wantErr: true,
  118. },
  119. }
  120. for name, tt := range tests {
  121. t.Run(name, func(t *testing.T) {
  122. qp := httputil.NewQueryParams(tt.values)
  123. got, err := ParseCloudCostRequest(qp)
  124. if (err != nil) != tt.wantErr {
  125. t.Errorf("ParseCloudCostRequest() error = %v, wantErr %v", err, tt.wantErr)
  126. return
  127. }
  128. if !reflect.DeepEqual(got, tt.want) {
  129. t.Errorf("ParseCloudCostRequest() got = %v, want %v", got, tt.want)
  130. }
  131. })
  132. }
  133. }
  134. func TestParseCloudCostAutocompleteRequest(t *testing.T) {
  135. windowStr := "2023-01-01T00:00:00Z,2023-01-02T00:00:00Z"
  136. validFilterStr := `service:"AmazonEC2"`
  137. parser := cloudcost.NewCloudCostFilterParser()
  138. validFilter, _ := parser.Parse(validFilterStr)
  139. tests := map[string]struct {
  140. values map[string][]string
  141. want *CloudCostAutocompleteRequest
  142. wantErr bool
  143. }{
  144. "missing window": {
  145. values: map[string][]string{"field": {"service"}},
  146. wantErr: true,
  147. },
  148. "missing field": {
  149. values: map[string][]string{"window": {windowStr}},
  150. wantErr: true,
  151. },
  152. "invalid window": {
  153. values: map[string][]string{
  154. "window": {"invalid"},
  155. "field": {"service"},
  156. },
  157. wantErr: true,
  158. },
  159. "open window": {
  160. values: map[string][]string{
  161. "window": {"2023-01-01T00:00:00Z,"},
  162. "field": {"service"},
  163. },
  164. wantErr: true,
  165. },
  166. "invalid filter": {
  167. values: map[string][]string{
  168. "window": {windowStr},
  169. "field": {"service"},
  170. "filter": {"invalid"},
  171. },
  172. wantErr: true,
  173. },
  174. "valid request": {
  175. values: map[string][]string{
  176. "window": {windowStr},
  177. "field": {"service"},
  178. "filter": {validFilterStr},
  179. "search": {"ec2"},
  180. "limit": {"25"},
  181. },
  182. want: &CloudCostAutocompleteRequest{
  183. Search: "ec2",
  184. Field: "service",
  185. Limit: 25,
  186. Filter: validFilter,
  187. },
  188. wantErr: false,
  189. },
  190. }
  191. for name, tt := range tests {
  192. t.Run(name, func(t *testing.T) {
  193. qp := httputil.NewQueryParams(tt.values)
  194. got, err := ParseCloudCostAutocompleteRequest(qp)
  195. if (err != nil) != tt.wantErr {
  196. t.Fatalf("ParseCloudCostAutocompleteRequest() error = %v, wantErr %v", err, tt.wantErr)
  197. }
  198. if tt.wantErr {
  199. return
  200. }
  201. if got.Search != tt.want.Search || got.Field != tt.want.Field || got.Limit != tt.want.Limit {
  202. t.Fatalf("unexpected request: got=%+v want=%+v", got, tt.want)
  203. }
  204. if got.Window.IsOpen() {
  205. t.Fatal("expected closed window")
  206. }
  207. })
  208. }
  209. }