queryservice_helper_test.go 6.0 KB

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