github.com/rohankumardubey/aresdb@v0.0.2-0.20190517170215-e54e3ca06b9c/api/schema_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  	"encoding/json"
    20  	"errors"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"net/http"
    24  	"net/http/httptest"
    25  
    26  	"github.com/uber/aresdb/memstore"
    27  	memMocks "github.com/uber/aresdb/memstore/mocks"
    28  	metaCom "github.com/uber/aresdb/metastore/common"
    29  	"github.com/uber/aresdb/metastore/mocks"
    30  
    31  	"github.com/gorilla/mux"
    32  	"github.com/onsi/ginkgo"
    33  	. "github.com/onsi/gomega"
    34  	"github.com/stretchr/testify/mock"
    35  	"github.com/uber/aresdb/metastore"
    36  	"github.com/uber/aresdb/utils"
    37  )
    38  
    39  var _ = ginkgo.Describe("SchemaHandler", func() {
    40  
    41  	var testServer *httptest.Server
    42  	var hostPort string
    43  	var testTable = metaCom.Table{
    44  		Name: "testTable",
    45  		Columns: []metaCom.Column{
    46  			{
    47  				Name: "col1",
    48  				Type: "Int32",
    49  			},
    50  		},
    51  		PrimaryKeyColumns: []int{0},
    52  	}
    53  	var testTableSchema = memstore.TableSchema{
    54  		EnumDicts: map[string]memstore.EnumDict{
    55  			"testColumn": {
    56  				ReverseDict: []string{"a", "b", "c"},
    57  				Dict: map[string]int{
    58  					"a": 0,
    59  					"b": 1,
    60  					"c": 2,
    61  				},
    62  			},
    63  		},
    64  		Schema: testTable,
    65  	}
    66  
    67  	testMetaStore := &mocks.MetaStore{}
    68  	var testMemStore *memMocks.MemStore
    69  	var schemaHandler *SchemaHandler
    70  
    71  	ginkgo.BeforeEach(func() {
    72  		testMemStore = CreateMemStore(&testTableSchema, 0, nil, nil)
    73  		schemaHandler = NewSchemaHandler(testMetaStore)
    74  		testRouter := mux.NewRouter()
    75  		schemaHandler.Register(testRouter.PathPrefix("/schema").Subrouter())
    76  		testServer = httptest.NewUnstartedServer(WithPanicHandling(testRouter))
    77  		testServer.Start()
    78  		hostPort = testServer.Listener.Addr().String()
    79  	})
    80  
    81  	ginkgo.AfterEach(func() {
    82  		testServer.Close()
    83  	})
    84  
    85  	ginkgo.It("ListTables should work", func() {
    86  		testMemStore.On("GetSchemas").Return(map[string]*memstore.TableSchema{"testTable": nil})
    87  		testMetaStore.On("ListTables").Return([]string{"testTable"}, nil)
    88  		hostPort := testServer.Listener.Addr().String()
    89  		resp, err := http.Get(fmt.Sprintf("http://%s/schema/tables", hostPort))
    90  		Ω(err).Should(BeNil())
    91  		respBody, err := ioutil.ReadAll(resp.Body)
    92  		Ω(err).Should(BeNil())
    93  		Ω(resp.StatusCode).Should(Equal(http.StatusOK))
    94  		Ω(respBody).Should(Equal([]byte(`["testTable"]`)))
    95  	})
    96  
    97  	ginkgo.It("GetTable should work", func() {
    98  		testMetaStore.On("GetTable", "testTable").Return(&testTable, nil)
    99  		testMetaStore.On("GetTable", "unknown").Return(nil, metastore.ErrTableDoesNotExist)
   100  		resp, err := http.Get(fmt.Sprintf("http://%s/schema/tables/%s", hostPort, "testTable"))
   101  		Ω(resp.StatusCode).Should(Equal(http.StatusOK))
   102  		Ω(err).Should(BeNil())
   103  		respBody, err := ioutil.ReadAll(resp.Body)
   104  		Ω(err).Should(BeNil())
   105  		respTable := metaCom.Table{}
   106  		json.Unmarshal(respBody, &respTable)
   107  		Ω(respTable).Should(Equal(testTableSchema.Schema))
   108  
   109  		Ω(resp.StatusCode).Should(Equal(http.StatusOK))
   110  
   111  		resp, err = http.Get(fmt.Sprintf("http://%s/schema/tables/%s", hostPort, "unknown"))
   112  		Ω(err).Should(BeNil())
   113  		Ω(resp.StatusCode).Should(Equal(http.StatusNotFound))
   114  	})
   115  
   116  	ginkgo.It("AddTable should work", func() {
   117  
   118  		tableSchemaBytes, _ := json.Marshal(testTableSchema.Schema)
   119  
   120  		testMetaStore.On("CreateTable", mock.Anything).Return(nil).Once()
   121  		resp, _ := http.Post(fmt.Sprintf("http://%s/schema/tables", hostPort), "application/json", bytes.NewBuffer(tableSchemaBytes))
   122  		Ω(resp.StatusCode).Should(Equal(http.StatusOK))
   123  
   124  		var createdTableSchema *metaCom.Table
   125  		testMetaStore.On("CreateTable", mock.Anything).Run(func(args mock.Arguments) {
   126  			createdTableSchema = args.Get(0).(*metaCom.Table)
   127  		}).Return(nil).Once()
   128  		resp, _ = http.Post(fmt.Sprintf("http://%s/schema/tables", hostPort), "application/json", bytes.NewBuffer(tableSchemaBytes))
   129  		Ω(resp.StatusCode).Should(Equal(http.StatusOK))
   130  		Ω(createdTableSchema).ShouldNot(BeNil())
   131  		Ω(createdTableSchema.Config).Should(Equal(metastore.DefaultTableConfig))
   132  
   133  		testMetaStore.On("CreateTable", mock.Anything).Return(errors.New("Failed to create table")).Once()
   134  		resp, _ = http.Post(fmt.Sprintf("http://%s/schema/tables", hostPort), "application/json", bytes.NewBuffer(tableSchemaBytes))
   135  		Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError))
   136  
   137  		tableSchemaBytes = []byte(`{"name": ""`)
   138  		resp, _ = http.Post(fmt.Sprintf("http://%s/schema/tables", hostPort), "application/json", bytes.NewBuffer(tableSchemaBytes))
   139  		Ω(resp.StatusCode).Should(Equal(http.StatusBadRequest))
   140  	})
   141  
   142  	ginkgo.It("UpdateTableConfig should work", func() {
   143  		tableSchemaBytes, _ := json.Marshal(testTableSchema.Schema)
   144  
   145  		testMetaStore.On("CreateTable", mock.Anything, mock.Anything).Return(nil).Once()
   146  		resp, _ := http.Post(fmt.Sprintf("http://%s/schema/tables", hostPort), "application/json", bytes.NewBuffer(tableSchemaBytes))
   147  		Ω(resp.StatusCode).Should(Equal(http.StatusOK))
   148  
   149  		testMetaStore.On("UpdateTableConfig", mock.Anything, mock.Anything).Return(nil).Once()
   150  		req, _ := http.NewRequest(http.MethodPut, fmt.Sprintf("http://%s/schema/tables/%s", hostPort, testTableSchema.Schema.Name), bytes.NewBuffer(tableSchemaBytes))
   151  		resp, _ = http.DefaultClient.Do(req)
   152  		Ω(resp.StatusCode).Should(Equal(http.StatusOK))
   153  
   154  		testMetaStore.On("UpdateTableConfig", mock.Anything, mock.Anything).Return(errors.New("Failed to create table")).Once()
   155  		req, _ = http.NewRequest(http.MethodPut, fmt.Sprintf("http://%s/schema/tables/%s", hostPort, testTableSchema.Schema.Name), bytes.NewBuffer(tableSchemaBytes))
   156  		resp, _ = http.DefaultClient.Do(req)
   157  		Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError))
   158  
   159  		tableSchemaBytes = []byte(`{"name": ""`)
   160  		req, _ = http.NewRequest(http.MethodPut, fmt.Sprintf("http://%s/schema/tables/%s", hostPort, testTableSchema.Schema.Name), bytes.NewBuffer(tableSchemaBytes))
   161  		resp, _ = http.DefaultClient.Do(req)
   162  		Ω(resp.StatusCode).Should(Equal(http.StatusBadRequest))
   163  	})
   164  
   165  	ginkgo.It("DeleteTable should work", func() {
   166  		testMetaStore.On("DeleteTable", mock.Anything).Return(nil).Once()
   167  		req, _ := http.NewRequest(http.MethodDelete, fmt.Sprintf("http://%s/schema/tables/%s", hostPort, "testTable"), &bytes.Buffer{})
   168  		resp, _ := http.DefaultClient.Do(req)
   169  		Ω(resp.StatusCode).Should(Equal(http.StatusOK))
   170  
   171  		testMetaStore.On("DeleteTable", mock.Anything).Return(errors.New("Failed to delete table")).Once()
   172  		req, _ = http.NewRequest(http.MethodDelete, fmt.Sprintf("http://%s/schema/tables/%s", hostPort, "testTable"), &bytes.Buffer{})
   173  		resp, _ = http.DefaultClient.Do(req)
   174  		Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError))
   175  		bs, err := ioutil.ReadAll(resp.Body)
   176  		Ω(err).Should(BeNil())
   177  		defer resp.Body.Close()
   178  
   179  		var errResp utils.APIError
   180  		err = json.Unmarshal(bs, &errResp)
   181  		Ω(err).Should(BeNil())
   182  		Ω(errResp.Message).Should(Equal("Failed to delete table"))
   183  	})
   184  
   185  	ginkgo.It("AddColumn should work", func() {
   186  		columnBytes := []byte(`{"name": "testCol", "type":"Int32", "defaultValue": "1"}`)
   187  		testMetaStore.On("AddColumn", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
   188  		resp, _ := http.Post(fmt.Sprintf("http://%s/schema/tables/%s/columns", hostPort, "testTable"), "application/json", bytes.NewBuffer(columnBytes))
   189  		Ω(resp.StatusCode).Should(Equal(http.StatusOK))
   190  
   191  		columnBytes = []byte(`{"name": "testCol", "type":"Int32"}`)
   192  		testMetaStore.On("AddColumn", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
   193  		resp, _ = http.Post(fmt.Sprintf("http://%s/schema/tables/%s/columns", hostPort, "testTable"), "application/json", bytes.NewBuffer(columnBytes))
   194  		Ω(resp.StatusCode).Should(Equal(http.StatusOK))
   195  
   196  		errorColumnBytes := []byte(`{"name": "testCol"`)
   197  		resp, _ = http.Post(fmt.Sprintf("http://%s/schema/tables/%s/columns", hostPort, "testTable"), "application/json", bytes.NewBuffer(errorColumnBytes))
   198  		Ω(resp.StatusCode).Should(Equal(http.StatusBadRequest))
   199  
   200  		testMetaStore.On("AddColumn", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("Failed to add columns")).Once()
   201  		resp, _ = http.Post(fmt.Sprintf("http://%s/schema/tables/%s/columns", hostPort, "testTable"), "application/json", bytes.NewBuffer(columnBytes))
   202  		Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError))
   203  	})
   204  
   205  	ginkgo.It("DeleteColumn should work", func() {
   206  		testMetaStore.On("DeleteColumn", mock.Anything, mock.Anything).Return(nil).Once()
   207  		req, _ := http.NewRequest(http.MethodDelete, fmt.Sprintf("http://%s/schema/tables/%s/columns/%s", hostPort, "testTable", "testColumn"), &bytes.Buffer{})
   208  		resp, _ := http.DefaultClient.Do(req)
   209  		Ω(resp.StatusCode).Should(Equal(http.StatusOK))
   210  
   211  		testMetaStore.On("DeleteColumn", mock.Anything, mock.Anything).Return(errors.New("Failed to delete columns")).Once()
   212  		req, _ = http.NewRequest(http.MethodDelete, fmt.Sprintf("http://%s/schema/tables/%s/columns/%s", hostPort, "testTable", "testColumn"), &bytes.Buffer{})
   213  		resp, _ = http.DefaultClient.Do(req)
   214  		Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError))
   215  	})
   216  
   217  	ginkgo.It("UpdateColumn should work", func() {
   218  		testColumnConfig1 := metaCom.ColumnConfig{
   219  			PreloadingDays: 2,
   220  			Priority:       3,
   221  		}
   222  
   223  		b, err := json.Marshal(testColumnConfig1)
   224  		Ω(err).Should(BeNil())
   225  
   226  		testMetaStore.On("UpdateColumn", mock.Anything, mock.Anything, mock.Anything).
   227  			Return(nil).Once()
   228  		req, _ := http.NewRequest(
   229  			http.MethodPut, fmt.Sprintf("http://%s/schema/tables/%s/columns/%s",
   230  				hostPort, "testTable", "testColumn"), bytes.NewReader(b))
   231  		resp, _ := http.DefaultClient.Do(req)
   232  		Ω(resp.StatusCode).Should(Equal(http.StatusOK))
   233  
   234  		testMetaStore.On("UpdateColumn", mock.Anything, mock.Anything).
   235  			Return(errors.New("failed to update columns")).Once()
   236  		req, _ = http.NewRequest(http.MethodPut, fmt.Sprintf("http://%s/schema/tables/%s/columns/%s",
   237  			hostPort, "testTable", "testColumn"), bytes.NewReader(b))
   238  		resp, _ = http.DefaultClient.Do(req)
   239  		Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError))
   240  	})
   241  })