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 }