github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/http_status_test.go (about)

     1  // Copyright 2020 PingCAP, 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 cdc
    15  
    16  import (
    17  	"bytes"
    18  	"fmt"
    19  	"io/ioutil"
    20  	"net/http"
    21  	"net/url"
    22  	"time"
    23  
    24  	"github.com/pingcap/check"
    25  	"github.com/pingcap/failpoint"
    26  	"github.com/pingcap/ticdc/pkg/config"
    27  	cerror "github.com/pingcap/ticdc/pkg/errors"
    28  	"github.com/pingcap/ticdc/pkg/util/testleak"
    29  	"go.etcd.io/etcd/clientv3/concurrency"
    30  )
    31  
    32  type httpStatusSuite struct{}
    33  
    34  var _ = check.Suite(&httpStatusSuite{})
    35  
    36  const retryTime = 20
    37  
    38  var advertiseAddr4Test = "127.0.0.1:8300"
    39  
    40  func (s *httpStatusSuite) waitUntilServerOnline(c *check.C) {
    41  	statusURL := fmt.Sprintf("http://%s/status", advertiseAddr4Test)
    42  	for i := 0; i < retryTime; i++ {
    43  		resp, err := http.Get(statusURL)
    44  		if err == nil {
    45  			_, err := ioutil.ReadAll(resp.Body)
    46  			c.Assert(err, check.IsNil)
    47  			resp.Body.Close()
    48  			return
    49  		}
    50  		time.Sleep(time.Millisecond * 50)
    51  	}
    52  	c.Errorf("failed to connect http status for %d retries in every 50ms", retryTime)
    53  }
    54  
    55  func (s *httpStatusSuite) TestHTTPStatus(c *check.C) {
    56  	defer testleak.AfterTest(c)()
    57  	conf := config.GetDefaultServerConfig()
    58  	conf.Addr = advertiseAddr4Test
    59  	conf.AdvertiseAddr = advertiseAddr4Test
    60  	config.StoreGlobalServerConfig(conf)
    61  	server, err := NewServer([]string{"http://127.0.0.1:2379"})
    62  	c.Assert(err, check.IsNil)
    63  	err = server.startStatusHTTP()
    64  	c.Assert(err, check.IsNil)
    65  	defer func() {
    66  		c.Assert(server.statusServer.Close(), check.IsNil)
    67  	}()
    68  
    69  	s.waitUntilServerOnline(c)
    70  
    71  	testPprof(c)
    72  	testReisgnOwner(c)
    73  	testHandleChangefeedAdmin(c)
    74  	testHandleRebalance(c)
    75  	testHandleMoveTable(c)
    76  	testHandleChangefeedQuery(c)
    77  	testHandleFailpoint(c)
    78  }
    79  
    80  func testPprof(c *check.C) {
    81  	resp, err := http.Get(fmt.Sprintf("http://%s/debug/pprof/cmdline", advertiseAddr4Test))
    82  	c.Assert(err, check.IsNil)
    83  	defer resp.Body.Close()
    84  	c.Assert(resp.StatusCode, check.Equals, 200)
    85  	_, err = ioutil.ReadAll(resp.Body)
    86  	c.Assert(err, check.IsNil)
    87  }
    88  
    89  func testReisgnOwner(c *check.C) {
    90  	uri := fmt.Sprintf("http://%s/capture/owner/resign", advertiseAddr4Test)
    91  	testHTTPPostOnly(c, uri)
    92  	testRequestNonOwnerFailed(c, uri)
    93  }
    94  
    95  func testHandleChangefeedAdmin(c *check.C) {
    96  	uri := fmt.Sprintf("http://%s/capture/owner/admin", advertiseAddr4Test)
    97  	testHTTPPostOnly(c, uri)
    98  	testRequestNonOwnerFailed(c, uri)
    99  }
   100  
   101  func testHandleRebalance(c *check.C) {
   102  	uri := fmt.Sprintf("http://%s/capture/owner/rebalance_trigger", advertiseAddr4Test)
   103  	testHTTPPostOnly(c, uri)
   104  	testRequestNonOwnerFailed(c, uri)
   105  }
   106  
   107  func testHandleMoveTable(c *check.C) {
   108  	uri := fmt.Sprintf("http://%s/capture/owner/move_table", advertiseAddr4Test)
   109  	testHTTPPostOnly(c, uri)
   110  	testRequestNonOwnerFailed(c, uri)
   111  }
   112  
   113  func testHandleChangefeedQuery(c *check.C) {
   114  	uri := fmt.Sprintf("http://%s/capture/owner/changefeed/query", advertiseAddr4Test)
   115  	testHTTPPostOnly(c, uri)
   116  	testRequestNonOwnerFailed(c, uri)
   117  }
   118  
   119  func testHTTPPostOnly(c *check.C, uri string) {
   120  	resp, err := http.Get(uri)
   121  	c.Assert(err, check.IsNil)
   122  	data, err := ioutil.ReadAll(resp.Body)
   123  	c.Assert(err, check.IsNil)
   124  	defer resp.Body.Close()
   125  	c.Assert(resp.StatusCode, check.Equals, http.StatusBadRequest)
   126  	c.Assert(string(data), check.Equals, cerror.ErrSupportPostOnly.Error())
   127  }
   128  
   129  func testRequestNonOwnerFailed(c *check.C, uri string) {
   130  	resp, err := http.PostForm(uri, url.Values{})
   131  	c.Assert(err, check.IsNil)
   132  	data, err := ioutil.ReadAll(resp.Body)
   133  	c.Assert(err, check.IsNil)
   134  	defer resp.Body.Close()
   135  	c.Assert(resp.StatusCode, check.Equals, http.StatusBadRequest)
   136  	c.Assert(string(data), check.Equals, concurrency.ErrElectionNotLeader.Error())
   137  }
   138  
   139  func testHandleFailpoint(c *check.C) {
   140  	fp := "github.com/pingcap/ticdc/cdc/TestHandleFailpoint"
   141  	uri := fmt.Sprintf("http://%s/debug/fail/%s", advertiseAddr4Test, fp)
   142  	body := bytes.NewReader([]byte("return(true)"))
   143  	req, err := http.NewRequest("PUT", uri, body)
   144  	c.Assert(err, check.IsNil)
   145  
   146  	resp, err := http.DefaultClient.Do(req)
   147  	c.Assert(err, check.IsNil)
   148  	defer resp.Body.Close()
   149  	c.Assert(resp.StatusCode, check.GreaterEqual, 200)
   150  	c.Assert(resp.StatusCode, check.Less, 300)
   151  
   152  	failpointHit := false
   153  	failpoint.Inject("TestHandleFailpoint", func() {
   154  		failpointHit = true
   155  	})
   156  	c.Assert(failpointHit, check.IsTrue)
   157  
   158  	req, err = http.NewRequest("DELETE", uri, body)
   159  	c.Assert(err, check.IsNil)
   160  	resp, err = http.DefaultClient.Do(req)
   161  	c.Assert(err, check.IsNil)
   162  	defer resp.Body.Close()
   163  	c.Assert(resp.StatusCode, check.GreaterEqual, 200)
   164  	c.Assert(resp.StatusCode, check.Less, 300)
   165  
   166  	failpointHit = false
   167  	failpoint.Inject("TestHandleFailpoint", func() {
   168  		failpointHit = true
   169  	})
   170  	c.Assert(failpointHit, check.IsFalse)
   171  }