Files
tidb/br/pkg/pdutil/pd_test.go
2021-08-09 06:11:13 +08:00

235 lines
6.8 KiB
Go

// Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0.
package pdutil
import (
"context"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"github.com/coreos/go-semver/semver"
. "github.com/pingcap/check"
"github.com/pingcap/kvproto/pkg/metapb"
"github.com/pingcap/tidb/util/codec"
"github.com/tikv/pd/pkg/typeutil"
"github.com/tikv/pd/server/api"
"github.com/tikv/pd/server/core"
"github.com/tikv/pd/server/statistics"
)
func TestT(t *testing.T) {
TestingT(t)
}
type testPDControllerSuite struct {
}
var _ = Suite(&testPDControllerSuite{})
func (s *testPDControllerSuite) TestScheduler(c *C) {
ctx := context.Background()
scheduler := "balance-leader-scheduler"
mock := func(context.Context, string, string, *http.Client, string, io.Reader) ([]byte, error) {
return nil, errors.New("failed")
}
schedulerPauseCh := make(chan struct{})
pdController := &PdController{addrs: []string{"", ""}, schedulerPauseCh: schedulerPauseCh}
_, err := pdController.pauseSchedulersAndConfigWith(ctx, []string{scheduler}, nil, mock)
c.Assert(err, ErrorMatches, "failed")
go func() {
<-schedulerPauseCh
}()
err = pdController.resumeSchedulerWith(ctx, []string{scheduler}, mock)
c.Assert(err, IsNil)
cfg := map[string]interface{}{
"max-merge-region-keys": 0,
"max-snapshot": 1,
"enable-location-replacement": false,
"max-pending-peer-count": uint64(16),
}
_, err = pdController.pauseSchedulersAndConfigWith(ctx, []string{}, cfg, mock)
c.Assert(err, ErrorMatches, "failed to update PD.*")
go func() {
<-schedulerPauseCh
}()
_, err = pdController.listSchedulersWith(ctx, mock)
c.Assert(err, ErrorMatches, "failed")
mock = func(context.Context, string, string, *http.Client, string, io.Reader) ([]byte, error) {
return []byte(`["` + scheduler + `"]`), nil
}
_, err = pdController.pauseSchedulersAndConfigWith(ctx, []string{scheduler}, cfg, mock)
c.Assert(err, IsNil)
go func() {
<-schedulerPauseCh
}()
err = pdController.resumeSchedulerWith(ctx, []string{scheduler}, mock)
c.Assert(err, IsNil)
schedulers, err := pdController.listSchedulersWith(ctx, mock)
c.Assert(err, IsNil)
c.Assert(schedulers, HasLen, 1)
c.Assert(schedulers[0], Equals, scheduler)
}
func (s *testPDControllerSuite) TestGetClusterVersion(c *C) {
pdController := &PdController{addrs: []string{"", ""}} // two endpoints
counter := 0
mock := func(context.Context, string, string, *http.Client, string, io.Reader) ([]byte, error) {
counter++
if counter <= 1 {
return nil, errors.New("mock error")
}
return []byte(`test`), nil
}
ctx := context.Background()
respString, err := pdController.getClusterVersionWith(ctx, mock)
c.Assert(err, IsNil)
c.Assert(respString, Equals, "test")
mock = func(context.Context, string, string, *http.Client, string, io.Reader) ([]byte, error) {
return nil, errors.New("mock error")
}
_, err = pdController.getClusterVersionWith(ctx, mock)
c.Assert(err, NotNil)
}
func (s *testPDControllerSuite) TestRegionCount(c *C) {
regions := core.NewRegionsInfo()
regions.SetRegion(core.NewRegionInfo(&metapb.Region{
Id: 1,
StartKey: codec.EncodeBytes(nil, []byte{1, 1}),
EndKey: codec.EncodeBytes(nil, []byte{1, 3}),
RegionEpoch: &metapb.RegionEpoch{},
}, nil))
regions.SetRegion(core.NewRegionInfo(&metapb.Region{
Id: 2,
StartKey: codec.EncodeBytes(nil, []byte{1, 3}),
EndKey: codec.EncodeBytes(nil, []byte{1, 5}),
RegionEpoch: &metapb.RegionEpoch{},
}, nil))
regions.SetRegion(core.NewRegionInfo(&metapb.Region{
Id: 3,
StartKey: codec.EncodeBytes(nil, []byte{2, 3}),
EndKey: codec.EncodeBytes(nil, []byte{3, 4}),
RegionEpoch: &metapb.RegionEpoch{},
}, nil))
c.Assert(regions.Len(), Equals, 3)
mock := func(
_ context.Context, addr string, prefix string, _ *http.Client, _ string, _ io.Reader,
) ([]byte, error) {
query := fmt.Sprintf("%s/%s", addr, prefix)
u, e := url.Parse(query)
c.Assert(e, IsNil, Commentf("%s", query))
start := u.Query().Get("start_key")
end := u.Query().Get("end_key")
c.Log(hex.EncodeToString([]byte(start)))
c.Log(hex.EncodeToString([]byte(end)))
scanRegions := regions.ScanRange([]byte(start), []byte(end), 0)
stats := statistics.RegionStats{Count: len(scanRegions)}
ret, err := json.Marshal(stats)
c.Assert(err, IsNil)
return ret, nil
}
pdController := &PdController{addrs: []string{"http://mock"}}
ctx := context.Background()
resp, err := pdController.getRegionCountWith(ctx, mock, []byte{}, []byte{})
c.Assert(err, IsNil)
c.Assert(resp, Equals, 3)
resp, err = pdController.getRegionCountWith(ctx, mock, []byte{0}, []byte{0xff})
c.Assert(err, IsNil)
c.Assert(resp, Equals, 3)
resp, err = pdController.getRegionCountWith(ctx, mock, []byte{1, 2}, []byte{1, 4})
c.Assert(err, IsNil)
c.Assert(resp, Equals, 2)
}
func (s *testPDControllerSuite) TestPDVersion(c *C) {
v := []byte("\"v4.1.0-alpha1\"\n")
r := parseVersion(v)
expectV := semver.New("4.1.0-alpha1")
c.Assert(r.Major, Equals, expectV.Major)
c.Assert(r.Minor, Equals, expectV.Minor)
c.Assert(r.PreRelease, Equals, expectV.PreRelease)
}
func (s *testPDControllerSuite) TestPDRequestRetry(c *C) {
ctx := context.Background()
count := 0
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
count++
if count <= 5 {
w.WriteHeader(http.StatusGatewayTimeout)
return
}
w.WriteHeader(http.StatusOK)
}))
cli := http.DefaultClient
taddr := ts.URL
_, reqErr := pdRequest(ctx, taddr, "", cli, http.MethodGet, nil)
c.Assert(reqErr, IsNil)
ts.Close()
count = 0
ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
count++
if count <= 11 {
w.WriteHeader(http.StatusGatewayTimeout)
return
}
w.WriteHeader(http.StatusOK)
}))
defer ts.Close()
taddr = ts.URL
_, reqErr = pdRequest(ctx, taddr, "", cli, http.MethodGet, nil)
c.Assert(reqErr, NotNil)
}
func (s *testPDControllerSuite) TestStoreInfo(c *C) {
storeInfo := api.StoreInfo{
Status: &api.StoreStatus{
Capacity: typeutil.ByteSize(1024),
Available: typeutil.ByteSize(1024),
},
Store: &api.MetaStore{
StateName: "Tombstone",
},
}
mock := func(
_ context.Context, addr string, prefix string, _ *http.Client, _ string, _ io.Reader,
) ([]byte, error) {
query := fmt.Sprintf("%s/%s", addr, prefix)
c.Assert(query, Equals, "http://mock/pd/api/v1/store/1")
ret, err := json.Marshal(storeInfo)
c.Assert(err, IsNil)
return ret, nil
}
pdController := &PdController{addrs: []string{"http://mock"}}
ctx := context.Background()
resp, err := pdController.getStoreInfoWith(ctx, mock, 1)
c.Assert(err, IsNil)
c.Assert(resp, NotNil)
c.Assert(resp.Status, NotNil)
c.Assert(resp.Store.StateName, Equals, "Tombstone")
c.Assert(uint64(resp.Status.Available), Equals, uint64(1024))
}