github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/pdutil/pd_test.go (about)

     1  // Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0.
     2  
     3  package pdutil
     4  
     5  import (
     6  	"context"
     7  	"encoding/hex"
     8  	"encoding/json"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"net/http"
    13  	"net/http/httptest"
    14  	"net/url"
    15  	"testing"
    16  
    17  	"github.com/coreos/go-semver/semver"
    18  	. "github.com/pingcap/check"
    19  	"github.com/pingcap/kvproto/pkg/metapb"
    20  	"github.com/pingcap/tidb/util/codec"
    21  	"github.com/tikv/pd/pkg/typeutil"
    22  	"github.com/tikv/pd/server/api"
    23  	"github.com/tikv/pd/server/core"
    24  	"github.com/tikv/pd/server/statistics"
    25  )
    26  
    27  func TestT(t *testing.T) {
    28  	TestingT(t)
    29  }
    30  
    31  type testPDControllerSuite struct {
    32  }
    33  
    34  var _ = Suite(&testPDControllerSuite{})
    35  
    36  func (s *testPDControllerSuite) TestScheduler(c *C) {
    37  	ctx := context.Background()
    38  
    39  	scheduler := "balance-leader-scheduler"
    40  	mock := func(context.Context, string, string, *http.Client, string, io.Reader) ([]byte, error) {
    41  		return nil, errors.New("failed")
    42  	}
    43  	schedulerPauseCh := make(chan struct{})
    44  	pdController := &PdController{addrs: []string{"", ""}, schedulerPauseCh: schedulerPauseCh}
    45  
    46  	_, err := pdController.pauseSchedulersAndConfigWith(ctx, []string{scheduler}, nil, mock)
    47  	c.Assert(err, ErrorMatches, "failed")
    48  
    49  	go func() {
    50  		<-schedulerPauseCh
    51  	}()
    52  	err = pdController.resumeSchedulerWith(ctx, []string{scheduler}, mock)
    53  	c.Assert(err, IsNil)
    54  
    55  	cfg := map[string]interface{}{
    56  		"max-merge-region-keys":       0,
    57  		"max-snapshot":                1,
    58  		"enable-location-replacement": false,
    59  		"max-pending-peer-count":      uint64(16),
    60  	}
    61  	_, err = pdController.pauseSchedulersAndConfigWith(ctx, []string{}, cfg, mock)
    62  	c.Assert(err, ErrorMatches, "failed to update PD.*")
    63  	go func() {
    64  		<-schedulerPauseCh
    65  	}()
    66  
    67  	_, err = pdController.listSchedulersWith(ctx, mock)
    68  	c.Assert(err, ErrorMatches, "failed")
    69  
    70  	mock = func(context.Context, string, string, *http.Client, string, io.Reader) ([]byte, error) {
    71  		return []byte(`["` + scheduler + `"]`), nil
    72  	}
    73  
    74  	_, err = pdController.pauseSchedulersAndConfigWith(ctx, []string{scheduler}, cfg, mock)
    75  	c.Assert(err, IsNil)
    76  
    77  	go func() {
    78  		<-schedulerPauseCh
    79  	}()
    80  	err = pdController.resumeSchedulerWith(ctx, []string{scheduler}, mock)
    81  	c.Assert(err, IsNil)
    82  
    83  	schedulers, err := pdController.listSchedulersWith(ctx, mock)
    84  	c.Assert(err, IsNil)
    85  	c.Assert(schedulers, HasLen, 1)
    86  	c.Assert(schedulers[0], Equals, scheduler)
    87  }
    88  
    89  func (s *testPDControllerSuite) TestGetClusterVersion(c *C) {
    90  	pdController := &PdController{addrs: []string{"", ""}} // two endpoints
    91  	counter := 0
    92  	mock := func(context.Context, string, string, *http.Client, string, io.Reader) ([]byte, error) {
    93  		counter++
    94  		if counter <= 1 {
    95  			return nil, errors.New("mock error")
    96  		}
    97  		return []byte(`test`), nil
    98  	}
    99  
   100  	ctx := context.Background()
   101  	respString, err := pdController.getClusterVersionWith(ctx, mock)
   102  	c.Assert(err, IsNil)
   103  	c.Assert(respString, Equals, "test")
   104  
   105  	mock = func(context.Context, string, string, *http.Client, string, io.Reader) ([]byte, error) {
   106  		return nil, errors.New("mock error")
   107  	}
   108  	_, err = pdController.getClusterVersionWith(ctx, mock)
   109  	c.Assert(err, NotNil)
   110  }
   111  
   112  func (s *testPDControllerSuite) TestRegionCount(c *C) {
   113  	regions := core.NewRegionsInfo()
   114  	regions.SetRegion(core.NewRegionInfo(&metapb.Region{
   115  		Id:          1,
   116  		StartKey:    codec.EncodeBytes(nil, []byte{1, 1}),
   117  		EndKey:      codec.EncodeBytes(nil, []byte{1, 3}),
   118  		RegionEpoch: &metapb.RegionEpoch{},
   119  	}, nil))
   120  	regions.SetRegion(core.NewRegionInfo(&metapb.Region{
   121  		Id:          2,
   122  		StartKey:    codec.EncodeBytes(nil, []byte{1, 3}),
   123  		EndKey:      codec.EncodeBytes(nil, []byte{1, 5}),
   124  		RegionEpoch: &metapb.RegionEpoch{},
   125  	}, nil))
   126  	regions.SetRegion(core.NewRegionInfo(&metapb.Region{
   127  		Id:          3,
   128  		StartKey:    codec.EncodeBytes(nil, []byte{2, 3}),
   129  		EndKey:      codec.EncodeBytes(nil, []byte{3, 4}),
   130  		RegionEpoch: &metapb.RegionEpoch{},
   131  	}, nil))
   132  	c.Assert(regions.Len(), Equals, 3)
   133  
   134  	mock := func(
   135  		_ context.Context, addr string, prefix string, _ *http.Client, _ string, _ io.Reader,
   136  	) ([]byte, error) {
   137  		query := fmt.Sprintf("%s/%s", addr, prefix)
   138  		u, e := url.Parse(query)
   139  		c.Assert(e, IsNil, Commentf("%s", query))
   140  		start := u.Query().Get("start_key")
   141  		end := u.Query().Get("end_key")
   142  		c.Log(hex.EncodeToString([]byte(start)))
   143  		c.Log(hex.EncodeToString([]byte(end)))
   144  		scanRegions := regions.ScanRange([]byte(start), []byte(end), 0)
   145  		stats := statistics.RegionStats{Count: len(scanRegions)}
   146  		ret, err := json.Marshal(stats)
   147  		c.Assert(err, IsNil)
   148  		return ret, nil
   149  	}
   150  
   151  	pdController := &PdController{addrs: []string{"http://mock"}}
   152  	ctx := context.Background()
   153  	resp, err := pdController.getRegionCountWith(ctx, mock, []byte{}, []byte{})
   154  	c.Assert(err, IsNil)
   155  	c.Assert(resp, Equals, 3)
   156  
   157  	resp, err = pdController.getRegionCountWith(ctx, mock, []byte{0}, []byte{0xff})
   158  	c.Assert(err, IsNil)
   159  	c.Assert(resp, Equals, 3)
   160  
   161  	resp, err = pdController.getRegionCountWith(ctx, mock, []byte{1, 2}, []byte{1, 4})
   162  	c.Assert(err, IsNil)
   163  	c.Assert(resp, Equals, 2)
   164  }
   165  
   166  func (s *testPDControllerSuite) TestPDVersion(c *C) {
   167  	v := []byte("\"v4.1.0-alpha1\"\n")
   168  	r := parseVersion(v)
   169  	expectV := semver.New("4.1.0-alpha1")
   170  	c.Assert(r.Major, Equals, expectV.Major)
   171  	c.Assert(r.Minor, Equals, expectV.Minor)
   172  	c.Assert(r.PreRelease, Equals, expectV.PreRelease)
   173  }
   174  
   175  func (s *testPDControllerSuite) TestPDRequestRetry(c *C) {
   176  	ctx := context.Background()
   177  	count := 0
   178  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   179  		count++
   180  		if count <= 5 {
   181  			w.WriteHeader(http.StatusGatewayTimeout)
   182  			return
   183  		}
   184  		w.WriteHeader(http.StatusOK)
   185  	}))
   186  	cli := http.DefaultClient
   187  	taddr := ts.URL
   188  	_, reqErr := pdRequest(ctx, taddr, "", cli, http.MethodGet, nil)
   189  	c.Assert(reqErr, IsNil)
   190  	ts.Close()
   191  	count = 0
   192  	ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   193  		count++
   194  		if count <= 11 {
   195  			w.WriteHeader(http.StatusGatewayTimeout)
   196  			return
   197  		}
   198  		w.WriteHeader(http.StatusOK)
   199  	}))
   200  	defer ts.Close()
   201  	taddr = ts.URL
   202  	_, reqErr = pdRequest(ctx, taddr, "", cli, http.MethodGet, nil)
   203  	c.Assert(reqErr, NotNil)
   204  }
   205  
   206  func (s *testPDControllerSuite) TestStoreInfo(c *C) {
   207  	storeInfo := api.StoreInfo{
   208  		Status: &api.StoreStatus{
   209  			Capacity:  typeutil.ByteSize(1024),
   210  			Available: typeutil.ByteSize(1024),
   211  		},
   212  		Store: &api.MetaStore{
   213  			StateName: "Tombstone",
   214  		},
   215  	}
   216  	mock := func(
   217  		_ context.Context, addr string, prefix string, _ *http.Client, _ string, _ io.Reader,
   218  	) ([]byte, error) {
   219  		query := fmt.Sprintf("%s/%s", addr, prefix)
   220  		c.Assert(query, Equals, "http://mock/pd/api/v1/store/1")
   221  		ret, err := json.Marshal(storeInfo)
   222  		c.Assert(err, IsNil)
   223  		return ret, nil
   224  	}
   225  
   226  	pdController := &PdController{addrs: []string{"http://mock"}}
   227  	ctx := context.Background()
   228  	resp, err := pdController.getStoreInfoWith(ctx, mock, 1)
   229  	c.Assert(err, IsNil)
   230  	c.Assert(resp, NotNil)
   231  	c.Assert(resp.Status, NotNil)
   232  	c.Assert(resp.Store.StateName, Equals, "Tombstone")
   233  	c.Assert(uint64(resp.Status.Available), Equals, uint64(1024))
   234  }