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 })