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] = &regionsStat
   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  }