github.com/rohankumardubey/aresdb@v0.0.2-0.20190517170215-e54e3ca06b9c/client/connector_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 client
    16  
    17  import (
    18  	"encoding/json"
    19  	"net/http"
    20  	"net/http/httptest"
    21  	"regexp"
    22  	"strings"
    23  
    24  	"io/ioutil"
    25  	"time"
    26  
    27  	"github.com/onsi/ginkgo"
    28  	. "github.com/onsi/gomega"
    29  	"github.com/uber/aresdb/common"
    30  	memCom "github.com/uber/aresdb/memstore/common"
    31  	metaCom "github.com/uber/aresdb/metastore/common"
    32  	"github.com/uber/aresdb/utils"
    33  	"go.uber.org/zap"
    34  )
    35  
    36  var _ = ginkgo.Describe("AresDB connector", func() {
    37  	var hostPort string
    38  	var testServer *httptest.Server
    39  	testTableNames := []string{"a"}
    40  	re := regexp.MustCompile("/schema/tables/a/columns/(.+)/enum-cases")
    41  	testTables := map[string]metaCom.Table{
    42  		"a": {
    43  			Name: "a",
    44  			Columns: []metaCom.Column{
    45  				{
    46  					Name: "col0",
    47  					Type: metaCom.Int32,
    48  				},
    49  				{
    50  					Name: "col1",
    51  					Type: metaCom.Int32,
    52  				},
    53  				{
    54  					Name: "col1_hll",
    55  					Type: metaCom.UUID,
    56  					HLLConfig: metaCom.HLLConfig{
    57  						IsHLLColumn: true,
    58  					},
    59  				},
    60  				{
    61  					Name: "col2",
    62  					Type: metaCom.BigEnum,
    63  				},
    64  				{
    65  					Name: "col3",
    66  					Type: metaCom.Bool,
    67  				},
    68  				{
    69  					Name:              "col4",
    70  					Type:              metaCom.BigEnum,
    71  					DisableAutoExpand: true,
    72  					CaseInsensitive:   true,
    73  				},
    74  				{
    75  					Name:              "col5",
    76  					Type:              metaCom.BigEnum,
    77  					DisableAutoExpand: true,
    78  					CaseInsensitive:   true,
    79  				},
    80  			},
    81  			PrimaryKeyColumns: []int{1},
    82  			IsFactTable:       true,
    83  		},
    84  	}
    85  
    86  	// this is the enum cases at first
    87  	initialColumn2EnumCases := map[string][]string{
    88  		"col2": {"1"},
    89  		"col4": {"a"},
    90  		"col5": {"A"},
    91  	}
    92  
    93  	// extendedEnumIDs
    94  	column2extendedEnumIDs := []int{2}
    95  
    96  	var insertBytes []byte
    97  	ginkgo.BeforeEach(func() {
    98  		testServer = httptest.NewUnstartedServer(
    99  			http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   100  				if strings.HasSuffix(r.URL.Path, "tables") && r.Method == http.MethodGet {
   101  					tableListBytes, _ := json.Marshal(testTableNames)
   102  					w.WriteHeader(http.StatusOK)
   103  					w.Write(tableListBytes)
   104  				} else if strings.HasSuffix(r.URL.Path, "tables/a") && r.Method == http.MethodGet {
   105  					tableBytes, _ := json.Marshal(testTables["a"])
   106  					w.WriteHeader(http.StatusOK)
   107  					w.Write(tableBytes)
   108  				} else if strings.HasSuffix(r.URL.Path, "enum-cases") {
   109  					if r.Method == http.MethodGet {
   110  						column := string(re.FindSubmatch([]byte(r.URL.Path))[1])
   111  						var enumBytes []byte
   112  						if enumCases, ok := initialColumn2EnumCases[column]; ok {
   113  							enumBytes, _ = json.Marshal(enumCases)
   114  						}
   115  
   116  						w.WriteHeader(http.StatusOK)
   117  						w.Write(enumBytes)
   118  					} else if r.Method == http.MethodPost {
   119  						enumIDBytes, _ := json.Marshal(column2extendedEnumIDs)
   120  						w.WriteHeader(http.StatusOK)
   121  						w.Write(enumIDBytes)
   122  					}
   123  				} else if strings.Contains(r.URL.Path, "data") && r.Method == http.MethodPost {
   124  					var err error
   125  					insertBytes, err = ioutil.ReadAll(r.Body)
   126  					if err != nil {
   127  						w.WriteHeader(http.StatusInternalServerError)
   128  					} else {
   129  						w.WriteHeader(http.StatusOK)
   130  					}
   131  				}
   132  			}))
   133  		testServer.Start()
   134  		hostPort = testServer.Listener.Addr().String()
   135  	})
   136  
   137  	ginkgo.AfterEach(func() {
   138  		testServer.Close()
   139  	})
   140  
   141  	ginkgo.It("Insert", func() {
   142  		config := ConnectorConfig{
   143  			Address: hostPort,
   144  		}
   145  
   146  		logger := zap.NewExample().Sugar()
   147  		rootScope, _, _ := common.NewNoopMetrics().NewRootScope()
   148  
   149  		errConfig := ConnectorConfig{
   150  			Address: "localhost:8888",
   151  		}
   152  		connector, err := errConfig.NewConnector(logger, rootScope)
   153  		Ω(err).ShouldNot(BeNil())
   154  
   155  		connector, err = config.NewConnector(logger, rootScope)
   156  		Ω(err).Should(BeNil())
   157  
   158  		insertBytes = nil
   159  		n, err := connector.Insert("a", []string{"col0", "col1", "col2", "col3", "col4", "col5"}, []Row{
   160  			{100, 1, "1", true, "a", "A"},
   161  			{200, int64(2), "2", false, "A", "a"},
   162  			{300, uint32(3), "2", "1", "b", "B"},
   163  			{400, int32(3), "1", "0", nil, nil},
   164  		})
   165  		Ω(err).Should(BeNil())
   166  		Ω(n).Should(Equal(4))
   167  
   168  		insertBytes = nil
   169  		utils.SetClockImplementation(func() time.Time {
   170  			return time.Unix(10, 0)
   171  		})
   172  		n, err = connector.Insert("a", []string{"col0", "col1", "col1_hll"}, []Row{
   173  			{100, 1, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}},
   174  		})
   175  		Ω(err).Should(BeNil())
   176  		Ω(n).Should(Equal(1))
   177  		Ω(insertBytes).Should(HaveLen(120))
   178  		Ω(insertBytes).Should(BeEquivalentTo([]byte{1, 0, 237, 254, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 89, 0, 0, 0, 100, 0, 0, 0, 108, 0, 0, 0, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 5, 0, 32, 0, 5, 0, 32, 0, 6, 0, 0, 0, 1, 0, 2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 8, 8, 5, 0, 0, 0, 0, 0}))
   179  		utils.ResetClockImplementation()
   180  
   181  		insertBytes = nil
   182  		// update primary key with addition
   183  		n, err = connector.Insert("a", []string{"col0", "col1", "col2", "col3", "col4", "col5"}, []Row{
   184  			{100, 1, "1", true, "a", "A"},
   185  			{200, int64(2), "2", false, "A", "a"},
   186  			{300, uint32(3), "2", "1", "b", "B"},
   187  			{400, int32(3), "1", "0", nil, nil},
   188  		}, 0, memCom.UpdateWithAddition, 0, 0, 0, 0)
   189  		Ω(err).ShouldNot(BeNil())
   190  		Ω(n).Should(Equal(0))
   191  
   192  		insertBytes = nil
   193  		// empty rows
   194  		n, err = connector.Insert("a", []string{"col0", "col1", "col2", "col3"}, []Row{})
   195  		Ω(err).Should(BeNil())
   196  		Ω(n).Should(Equal(0))
   197  
   198  		insertBytes = nil
   199  		// empty column names
   200  		n, err = connector.Insert("a", []string{}, []Row{})
   201  		Ω(err).ShouldNot(BeNil())
   202  		Ω(n).Should(Equal(0))
   203  
   204  		insertBytes = nil
   205  		// non matching length between column names and row
   206  		n, err = connector.Insert("a", []string{"col0", "col1", "col2", "col3"}, []Row{
   207  			{100, 1, "1", true},
   208  			{200, int64(2)},
   209  			{300, uint32(3), "2"},
   210  			{400, int32(3), "1", "0"},
   211  		})
   212  		Ω(err).ShouldNot(BeNil())
   213  		Ω(n).Should(Equal(0))
   214  
   215  		insertBytes = nil
   216  		// missing primary key columns
   217  		n, err = connector.Insert("a", []string{"col0", "col2", "col3"}, []Row{
   218  			{100, "1", true},
   219  			{200, "1", "0"},
   220  		})
   221  		Ω(err).ShouldNot(BeNil())
   222  		Ω(n).Should(Equal(0))
   223  
   224  		insertBytes = nil
   225  		// primary key is nil
   226  		n, err = connector.Insert("a", []string{"col0", "col1", "col2", "col3"}, []Row{
   227  			{100, nil, "1", true},
   228  			{200, int64(2), "1", "0"},
   229  		})
   230  		Ω(err).Should(BeNil())
   231  		Ω(n).Should(Equal(1))
   232  
   233  		insertBytes = nil
   234  		// primary key is nil
   235  		// missing time column
   236  		n, err = connector.Insert("a", []string{"col1", "col2", "col3"}, []Row{
   237  			{1, "1", true},
   238  			{int64(2), "1", "0"},
   239  		})
   240  		Ω(err).ShouldNot(BeNil())
   241  		Ω(n).Should(Equal(0))
   242  
   243  		insertBytes = nil
   244  		// time column is nil
   245  		n, err = connector.Insert("a", []string{"col0", "col1", "col2", "col3"}, []Row{
   246  			{nil, 1, "1", true},
   247  			{200, int64(2), "1", "0"},
   248  		})
   249  		Ω(err).Should(BeNil())
   250  		Ω(n).Should(Equal(1))
   251  
   252  		insertBytes = nil
   253  		// having non-string for enum column
   254  		n, err = connector.Insert("a", []string{"col0", "col1", "col2", "col3"}, []Row{
   255  			{100, 2, 1, true},
   256  			{200, int64(2), "1", "0"},
   257  		})
   258  		Ω(err).Should(BeNil())
   259  		Ω(n).Should(Equal(1))
   260  	})
   261  
   262  	ginkgo.It("computeHLLValue should work", func() {
   263  		tests := [][]interface{}{
   264  			{memCom.UUID, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, uint32(329736)},
   265  			{memCom.Uint32, 67305985, uint32(266211)},
   266  		}
   267  
   268  		for _, test := range tests {
   269  			dataType := test[0].(memCom.DataType)
   270  			input := test[1]
   271  			expected := test[2].(uint32)
   272  			out, err := computeHLLValue(dataType, input)
   273  			Ω(err).Should(BeNil())
   274  			Ω(out).Should(Equal(expected))
   275  		}
   276  	})
   277  })