github.com/rohankumardubey/aresdb@v0.0.2-0.20190517170215-e54e3ca06b9c/api/sql_query_handler_test.go (about)

     1  //  Copyright (c) 2017-2018 Uber Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package api
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"io/ioutil"
    21  	"net/http"
    22  	"net/http/httptest"
    23  
    24  	"github.com/uber/aresdb/memstore"
    25  	memMocks "github.com/uber/aresdb/memstore/mocks"
    26  	metaCom "github.com/uber/aresdb/metastore/common"
    27  
    28  	"github.com/gorilla/mux"
    29  	"github.com/onsi/ginkgo"
    30  	. "github.com/onsi/gomega"
    31  	"github.com/uber/aresdb/common"
    32  )
    33  
    34  var _ = ginkgo.Describe("QueryHandler SQL", func() {
    35  	var testServer *httptest.Server
    36  	var testSchema = memstore.NewTableSchema(&metaCom.Table{
    37  		Name:        "trips",
    38  		IsFactTable: false,
    39  		Columns: []metaCom.Column{
    40  			{
    41  				Name: "request_at",
    42  				Type: "Uint32",
    43  			},
    44  			{
    45  				Name: "fare_total",
    46  				Type: "Flaot",
    47  			},
    48  			{
    49  				Name: "city_id",
    50  				Type: "Uint16",
    51  			},
    52  			{
    53  				Name: "status",
    54  				Type: "SmallEnum",
    55  			},
    56  		},
    57  		Config: metaCom.TableConfig{
    58  			BatchSize: 10,
    59  		},
    60  	})
    61  
    62  	var memStore *memMocks.MemStore
    63  	ginkgo.BeforeEach(func() {
    64  		memStore = CreateMemStore(testSchema, 0, nil, CreateMockDiskStore())
    65  		queryHandler := NewQueryHandler(memStore, common.QueryConfig{
    66  			DeviceMemoryUtilization: 1.0,
    67  		})
    68  		testRouter := mux.NewRouter()
    69  		testRouter.HandleFunc("/sql", queryHandler.HandleSQL).Methods(http.MethodGet, http.MethodPost)
    70  		testServer = httptest.NewUnstartedServer(WithPanicHandling(testRouter))
    71  		testServer.Start()
    72  	})
    73  
    74  	ginkgo.AfterEach(func() {
    75  		testServer.Close()
    76  	})
    77  
    78  	ginkgo.It("HandleSQL should succeed on valid requests", func() {
    79  		hostPort := testServer.Listener.Addr().String()
    80  		// Invalid timeBucketizer days.
    81  		query := `
    82  			{
    83  			  "queries": [
    84  				"SELECT count(*) AS value FROM trips WHERE status='completed' AND aql_time_filter(request_at, \"24 hours ago\", \"this quarter-hour\", America/New_York) GROUP BY aql_time_bucket_hour(request_at, \"\", America/New_York) "
    85  			  ]
    86  			}
    87  		`
    88  		resp, err := http.Post(fmt.Sprintf("http://%s/sql", hostPort), "application/json", bytes.NewBuffer([]byte(query)))
    89  		Ω(err).Should(BeNil())
    90  		bs, err := ioutil.ReadAll(resp.Body)
    91  		Ω(err).Should(BeNil())
    92  		Ω(string(bs)).Should(MatchJSON(`{
    93  				"results": [
    94  				  {}
    95  				]
    96  			  }`))
    97  		Ω(resp.StatusCode).Should(Equal(http.StatusOK))
    98  	})
    99  
   100  	ginkgo.It("HandleSQL should fail on request that cannot be unmarshaled", func() {
   101  		hostPort := testServer.Listener.Addr().String()
   102  		resp, err := http.Post(fmt.Sprintf("http://%s/sql", hostPort), "application/json", bytes.NewBuffer([]byte{}))
   103  		Ω(err).Should(BeNil())
   104  		bs, err := ioutil.ReadAll(resp.Body)
   105  		Ω(err).Should(BeNil())
   106  		Ω(string(bs)).Should(MatchJSON(`
   107  			{"message":"Bad request: failed to unmarshal request body","cause":{"Offset":0}}
   108  		`))
   109  		Ω(resp.StatusCode).Should(Equal(http.StatusBadRequest))
   110  	})
   111  
   112  	ginkgo.It("HandleSQL should succeed on empty query requests", func() {
   113  		hostPort := testServer.Listener.Addr().String()
   114  		query := `
   115  			{
   116  			  "queries": [
   117  			  ]
   118  			}
   119  		`
   120  		resp, err := http.Post(fmt.Sprintf("http://%s/sql", hostPort), "application/json", bytes.NewBuffer([]byte(query)))
   121  		Ω(err).Should(BeNil())
   122  		bs, err := ioutil.ReadAll(resp.Body)
   123  		Ω(err).Should(BeNil())
   124  		Ω(resp.StatusCode).Should(Equal(http.StatusOK))
   125  		Ω(string(bs)).Should(MatchJSON(`
   126  			{
   127  				"results": []
   128              }
   129  		`))
   130  	})
   131  
   132  	ginkgo.It("HandleSQL should fail requests without queries", func() {
   133  		hostPort := testServer.Listener.Addr().String()
   134  		query := `
   135  			{"q":{}}
   136  		`
   137  		resp, err := http.Post(fmt.Sprintf("http://%s/sql", hostPort), "application/json", bytes.NewBuffer([]byte(query)))
   138  		Ω(err).Should(BeNil())
   139  		bs, err := ioutil.ReadAll(resp.Body)
   140  		Ω(err).Should(BeNil())
   141  		Ω(resp.StatusCode).Should(Equal(http.StatusBadRequest))
   142  		Ω(string(bs)).Should(ContainSubstring("Bad request: missing/invalid parameter"))
   143  	})
   144  })