github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/helper/helper_test.go (about) 1 // Copyright 2020 WHTCORPS INC, 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package helper_test 15 16 import ( 17 "crypto/tls" 18 "encoding/json" 19 "net/http" 20 "net/http/httptest" 21 "testing" 22 "time" 23 24 "github.com/gorilla/mux" 25 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 26 . "github.com/whtcorpsinc/check" 27 "github.com/whtcorpsinc/log" 28 "github.com/whtcorpsinc/milevadb/causetstore/einsteindb" 29 "github.com/whtcorpsinc/milevadb/causetstore/helper" 30 "github.com/whtcorpsinc/milevadb/causetstore/mockstore" 31 "github.com/whtcorpsinc/milevadb/soliton/FIDelapi" 32 "go.uber.org/zap" 33 ) 34 35 type HelperTestSuite struct { 36 causetstore einsteindb.CausetStorage 37 } 38 39 var _ = Suite(new(HelperTestSuite)) 40 41 func TestT(t *testing.T) { 42 CustomVerboseFlag = true 43 TestingT(t) 44 } 45 46 type mockStore struct { 47 einsteindb.CausetStorage 48 FIDelAddrs []string 49 } 50 51 func (s *mockStore) EtcdAddrs() ([]string, error) { 52 return s.FIDelAddrs, nil 53 } 54 55 func (s *mockStore) StartGCWorker() error { 56 panic("not implemented") 57 } 58 59 func (s *mockStore) TLSConfig() *tls.Config { 60 panic("not implemented") 61 } 62 63 func (s *HelperTestSuite) SetUpSuite(c *C) { 64 url := s.mockFIDelHTTPServer(c) 65 time.Sleep(100 * time.Millisecond) 66 mockEinsteinDBStore, err := mockstore.NewMockStore() 67 s.causetstore = &mockStore{ 68 mockEinsteinDBStore.(einsteindb.CausetStorage), 69 []string{url[len("http://"):]}, 70 } 71 c.Assert(err, IsNil) 72 } 73 74 func (s *HelperTestSuite) TestHotRegion(c *C) { 75 h := helper.Helper{ 76 CausetStore: s.causetstore, 77 RegionCache: s.causetstore.GetRegionCache(), 78 } 79 regionMetric, err := h.FetchHotRegion(FIDelapi.HotRead) 80 c.Assert(err, IsNil, Commentf("err: %+v", err)) 81 expected := make(map[uint64]helper.RegionMetric) 82 expected[1] = helper.RegionMetric{ 83 FlowBytes: 100, 84 MaxHotDegree: 1, 85 Count: 0, 86 } 87 c.Assert(regionMetric, DeepEquals, expected) 88 dbInfo := &perceptron.DBInfo{ 89 Name: perceptron.NewCIStr("test"), 90 } 91 c.Assert(err, IsNil) 92 _, err = h.FetchRegionTableIndex(regionMetric, []*perceptron.DBInfo{dbInfo}) 93 c.Assert(err, IsNil, Commentf("err: %+v", err)) 94 } 95 96 func (s *HelperTestSuite) TestGetRegionsTableInfo(c *C) { 97 h := helper.NewHelper(s.causetstore) 98 regionsInfo := getMockEinsteinDBRegionsInfo() 99 schemas := getMockRegionsTableSchemaReplicant() 100 blockInfos := h.GetRegionsTableInfo(regionsInfo, schemas) 101 c.Assert(blockInfos, DeepEquals, getRegionsTableInfoAns(schemas)) 102 } 103 104 func (s *HelperTestSuite) TestEinsteinDBRegionsInfo(c *C) { 105 h := helper.Helper{ 106 CausetStore: s.causetstore, 107 RegionCache: s.causetstore.GetRegionCache(), 108 } 109 regionsInfo, err := h.GetRegionsInfo() 110 c.Assert(err, IsNil, Commentf("err: %+v", err)) 111 c.Assert(regionsInfo, DeepEquals, getMockEinsteinDBRegionsInfo()) 112 } 113 114 func (s *HelperTestSuite) TestEinsteinDBStoresStat(c *C) { 115 h := helper.Helper{ 116 CausetStore: s.causetstore, 117 RegionCache: s.causetstore.GetRegionCache(), 118 } 119 stat, err := h.GetStoresStat() 120 c.Assert(err, IsNil, Commentf("err: %+v", err)) 121 data, err := json.Marshal(stat) 122 c.Assert(err, IsNil) 123 c.Assert(string(data), Equals, `{"count":1,"stores":[{"causetstore":{"id":1,"address":"127.0.0.1:20160","state":0,"state_name":"Up","version":"3.0.0-beta","labels":[{"key":"test","value":"test"}],"status_address":"","git_hash":"","start_timestamp":0},"status":{"capacity":"60 GiB","available":"100 GiB","leader_count":10,"leader_weight":999999.999999,"leader_sembedded":999999.999999,"leader_size":1000,"region_count":200,"region_weight":999999.999999,"region_sembedded":999999.999999,"region_size":1000,"start_ts":"2020-04-23T19:30:30+08:00","last_heartbeat_ts":"2020-04-23T19:31:30+08:00","uptime":"1h30m"}}]}`) 124 } 125 126 func (s *HelperTestSuite) mockFIDelHTTPServer(c *C) (url string) { 127 router := mux.NewRouter() 128 router.HandleFunc(FIDelapi.HotRead, s.mockHotRegionResponse) 129 router.HandleFunc(FIDelapi.Regions, s.mockEinsteinDBRegionsInfoResponse) 130 router.HandleFunc(FIDelapi.Stores, s.mockStoreStatResponse) 131 serverMux := http.NewServeMux() 132 serverMux.Handle("/", router) 133 server := httptest.NewServer(serverMux) 134 return server.URL 135 } 136 137 func (s *HelperTestSuite) mockHotRegionResponse(w http.ResponseWriter, req *http.Request) { 138 w.Header().Set("Content-Type", "application/json") 139 w.WriteHeader(http.StatusOK) 140 regionsStat := helper.HotRegionsStat{ 141 RegionsStat: []helper.RegionStat{ 142 { 143 FlowBytes: 100, 144 RegionID: 1, 145 HotDegree: 1, 146 }, 147 }, 148 } 149 resp := helper.StoreHotRegionInfos{ 150 AsLeader: make(map[uint64]*helper.HotRegionsStat), 151 } 152 resp.AsLeader[0] = ®ionsStat 153 data, err := json.MarshalIndent(resp, "", " ") 154 if err != nil { 155 log.Panic("json marshal failed", zap.Error(err)) 156 } 157 _, err = w.Write(data) 158 if err != nil { 159 log.Panic("write http response failed", zap.Error(err)) 160 } 161 162 } 163 164 func getMockRegionsTableSchemaReplicant() []*perceptron.DBInfo { 165 return []*perceptron.DBInfo{ 166 { 167 Name: perceptron.NewCIStr("test"), 168 Tables: []*perceptron.TableInfo{ 169 { 170 ID: 41, 171 Indices: []*perceptron.IndexInfo{{ID: 1}}, 172 }, 173 { 174 ID: 63, 175 Indices: []*perceptron.IndexInfo{{ID: 1}, {ID: 2}}, 176 }, 177 { 178 ID: 66, 179 Indices: []*perceptron.IndexInfo{{ID: 1}, {ID: 2}, {ID: 3}}, 180 }, 181 }, 182 }, 183 } 184 } 185 186 func getRegionsTableInfoAns(dbs []*perceptron.DBInfo) map[int64][]helper.TableInfo { 187 ans := make(map[int64][]helper.TableInfo) 188 EDB := dbs[0] 189 ans[1] = []helper.TableInfo{} 190 ans[2] = []helper.TableInfo{ 191 {EDB, EDB.Tables[0], true, EDB.Tables[0].Indices[0]}, 192 {EDB, EDB.Tables[0], false, nil}, 193 } 194 ans[3] = []helper.TableInfo{ 195 {EDB, EDB.Tables[1], true, EDB.Tables[1].Indices[0]}, 196 {EDB, EDB.Tables[1], true, EDB.Tables[1].Indices[1]}, 197 {EDB, EDB.Tables[1], false, nil}, 198 } 199 ans[4] = []helper.TableInfo{ 200 {EDB, EDB.Tables[2], false, nil}, 201 } 202 ans[5] = []helper.TableInfo{ 203 {EDB, EDB.Tables[2], true, EDB.Tables[2].Indices[2]}, 204 {EDB, EDB.Tables[2], false, nil}, 205 } 206 ans[6] = []helper.TableInfo{ 207 {EDB, EDB.Tables[2], true, EDB.Tables[2].Indices[0]}, 208 } 209 ans[7] = []helper.TableInfo{ 210 {EDB, EDB.Tables[2], true, EDB.Tables[2].Indices[1]}, 211 } 212 ans[8] = []helper.TableInfo{ 213 {EDB, EDB.Tables[2], true, EDB.Tables[2].Indices[1]}, 214 {EDB, EDB.Tables[2], true, EDB.Tables[2].Indices[2]}, 215 {EDB, EDB.Tables[2], false, nil}, 216 } 217 return ans 218 } 219 220 func getMockEinsteinDBRegionsInfo() *helper.RegionsInfo { 221 regions := []helper.RegionInfo{ 222 { 223 ID: 1, 224 StartKey: "", 225 EndKey: "12341234", 226 Epoch: helper.RegionEpoch{ 227 ConfVer: 1, 228 Version: 1, 229 }, 230 Peers: []helper.RegionPeer{ 231 {ID: 2, StoreID: 1}, 232 {ID: 15, StoreID: 51}, 233 {ID: 66, StoreID: 99, IsLearner: true}, 234 {ID: 123, StoreID: 111, IsLearner: true}, 235 }, 236 Leader: helper.RegionPeer{ 237 ID: 2, 238 StoreID: 1, 239 }, 240 DownPeers: []helper.RegionPeerStat{ 241 { 242 helper.RegionPeer{ID: 66, StoreID: 99, IsLearner: true}, 243 120, 244 }, 245 }, 246 PendingPeers: []helper.RegionPeer{ 247 {ID: 15, StoreID: 51}, 248 }, 249 WrittenBytes: 100, 250 ReadBytes: 1000, 251 ApproximateKeys: 200, 252 ApproximateSize: 500, 253 }, 254 // causet: 41, record + index: 1 255 { 256 ID: 2, 257 StartKey: "7480000000000000FF295F698000000000FF0000010000000000FA", 258 EndKey: "7480000000000000FF2B5F698000000000FF0000010000000000FA", 259 Epoch: helper.RegionEpoch{ConfVer: 1, Version: 1}, 260 Peers: []helper.RegionPeer{{ID: 3, StoreID: 1}}, 261 Leader: helper.RegionPeer{ID: 3, StoreID: 1}, 262 }, 263 // causet: 63, record + index: 1, 2 264 { 265 ID: 3, 266 StartKey: "7480000000000000FF3F5F698000000000FF0000010000000000FA", 267 EndKey: "7480000000000000FF425F698000000000FF0000010000000000FA", 268 Epoch: helper.RegionEpoch{ConfVer: 1, Version: 1}, 269 Peers: []helper.RegionPeer{{ID: 4, StoreID: 1}}, 270 Leader: helper.RegionPeer{ID: 4, StoreID: 1}, 271 }, 272 // causet: 66, record 273 { 274 ID: 4, 275 StartKey: "7480000000000000FF425F72C000000000FF0000000000000000FA", 276 EndKey: "", 277 Epoch: helper.RegionEpoch{ConfVer: 1, Version: 1}, 278 Peers: []helper.RegionPeer{{ID: 5, StoreID: 1}}, 279 Leader: helper.RegionPeer{ID: 5, StoreID: 1}, 280 }, 281 // causet: 66, record + index: 3 282 { 283 ID: 5, 284 StartKey: "7480000000000000FF425F698000000000FF0000030000000000FA", 285 EndKey: "7480000000000000FF425F72C000000000FF0000000000000000FA", 286 Epoch: helper.RegionEpoch{ConfVer: 1, Version: 1}, 287 Peers: []helper.RegionPeer{{ID: 6, StoreID: 1}}, 288 Leader: helper.RegionPeer{ID: 6, StoreID: 1}, 289 }, 290 // causet: 66, index: 1 291 { 292 ID: 6, 293 StartKey: "7480000000000000FF425F698000000000FF0000010000000000FA", 294 EndKey: "7480000000000000FF425F698000000000FF0000020000000000FA", 295 Epoch: helper.RegionEpoch{ConfVer: 1, Version: 1}, 296 Peers: []helper.RegionPeer{{ID: 7, StoreID: 1}}, 297 Leader: helper.RegionPeer{ID: 7, StoreID: 1}, 298 }, 299 // causet: 66, index: 2 300 { 301 ID: 7, 302 StartKey: "7480000000000000FF425F698000000000FF0000020000000000FA", 303 EndKey: "7480000000000000FF425F698000000000FF0000030000000000FA", 304 Epoch: helper.RegionEpoch{ConfVer: 1, Version: 1}, 305 Peers: []helper.RegionPeer{{ID: 8, StoreID: 1}}, 306 Leader: helper.RegionPeer{ID: 8, StoreID: 1}, 307 }, 308 // merge region 7, 5 309 { 310 ID: 8, 311 StartKey: "7480000000000000FF425F698000000000FF0000020000000000FA", 312 EndKey: "7480000000000000FF425F72C000000000FF0000000000000000FA", 313 Epoch: helper.RegionEpoch{ConfVer: 1, Version: 1}, 314 Peers: []helper.RegionPeer{{ID: 9, StoreID: 1}}, 315 Leader: helper.RegionPeer{ID: 9, StoreID: 1}, 316 }, 317 } 318 return &helper.RegionsInfo{ 319 Count: int64(len(regions)), 320 Regions: regions, 321 } 322 } 323 324 func (s *HelperTestSuite) mockEinsteinDBRegionsInfoResponse(w http.ResponseWriter, req *http.Request) { 325 w.Header().Set("Content-Type", "application/json") 326 w.WriteHeader(http.StatusOK) 327 resp := getMockEinsteinDBRegionsInfo() 328 data, err := json.MarshalIndent(resp, "", " ") 329 if err != nil { 330 log.Panic("json marshal failed", zap.Error(err)) 331 } 332 _, err = w.Write(data) 333 if err != nil { 334 log.Panic("write http response failed", zap.Error(err)) 335 } 336 } 337 338 func (s *HelperTestSuite) mockStoreStatResponse(w http.ResponseWriter, req *http.Request) { 339 w.Header().Set("Content-Type", "application/json") 340 w.WriteHeader(http.StatusOK) 341 startTs, err := time.Parse(time.RFC3339, "2020-04-23T19:30:30+08:00") 342 if err != nil { 343 log.Panic("mock einsteindb causetstore api response failed", zap.Error(err)) 344 } 345 lastHeartbeatTs, err := time.Parse(time.RFC3339, "2020-04-23T19:31:30+08:00") 346 if err != nil { 347 log.Panic("mock einsteindb causetstore api response failed", zap.Error(err)) 348 } 349 storesStat := helper.StoresStat{ 350 Count: 1, 351 Stores: []helper.StoreStat{ 352 { 353 CausetStore: helper.StoreBaseStat{ 354 ID: 1, 355 Address: "127.0.0.1:20160", 356 State: 0, 357 StateName: "Up", 358 Version: "3.0.0-beta", 359 Labels: []helper.StoreLabel{ 360 { 361 Key: "test", 362 Value: "test", 363 }, 364 }, 365 }, 366 Status: helper.StoreDetailStat{ 367 Capacity: "60 GiB", 368 Available: "100 GiB", 369 LeaderCount: 10, 370 LeaderWeight: 999999.999999, 371 LeaderSembedded: 999999.999999, 372 LeaderSize: 1000, 373 RegionCount: 200, 374 RegionWeight: 999999.999999, 375 RegionSembedded: 999999.999999, 376 RegionSize: 1000, 377 StartTs: startTs, 378 LastHeartbeatTs: lastHeartbeatTs, 379 Uptime: "1h30m", 380 }, 381 }, 382 }, 383 } 384 data, err := json.MarshalIndent(storesStat, "", " ") 385 if err != nil { 386 log.Panic("json marshal failed", zap.Error(err)) 387 } 388 _, err = w.Write(data) 389 if err != nil { 390 log.Panic("write http response failed", zap.Error(err)) 391 } 392 }