github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/allegrosql/server/http_handler_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 server
    15  
    16  import (
    17  	"bytes"
    18  	"crypto/tls"
    19  	"crypto/x509"
    20  	"crypto/x509/pkix"
    21  	"database/allegrosql"
    22  	"encoding/base64"
    23  	"encoding/json"
    24  	"fmt"
    25  	"io"
    26  	"io/ioutil"
    27  	"net"
    28  	"net/http"
    29  	"net/http/httputil"
    30  	"net/url"
    31  	"os"
    32  	"sort"
    33  	"strings"
    34  	"sync/atomic"
    35  	"time"
    36  
    37  	log "github.com/sirupsen/logrus"
    38  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    39  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    40  	. "github.com/whtcorpsinc/check"
    41  	"github.com/whtcorpsinc/ekvproto/pkg/ekvrpcpb"
    42  	"github.com/whtcorpsinc/failpoint"
    43  	zaplog "github.com/whtcorpsinc/log"
    44  	"github.com/whtcorpsinc/milevadb/blockcodec"
    45  	"github.com/whtcorpsinc/milevadb/causetstore/einsteindb"
    46  	"github.com/whtcorpsinc/milevadb/causetstore/helper"
    47  	"github.com/whtcorpsinc/milevadb/causetstore/mockstore"
    48  	"github.com/whtcorpsinc/milevadb/config"
    49  	"github.com/whtcorpsinc/milevadb/dbs"
    50  	"github.com/whtcorpsinc/milevadb/ekv"
    51  	"github.com/whtcorpsinc/milevadb/petri"
    52  	"github.com/whtcorpsinc/milevadb/soliton/codec"
    53  	"github.com/whtcorpsinc/milevadb/soliton/rowcodec"
    54  	"github.com/whtcorpsinc/milevadb/soliton/versioninfo"
    55  	"github.com/whtcorpsinc/milevadb/spacetime"
    56  	"github.com/whtcorpsinc/milevadb/stochastik"
    57  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    58  	"github.com/whtcorpsinc/milevadb/stochastikctx/binloginfo"
    59  	"github.com/whtcorpsinc/milevadb/stochastikctx/stmtctx"
    60  	"github.com/whtcorpsinc/milevadb/stochastikctx/variable"
    61  	"github.com/whtcorpsinc/milevadb/types"
    62  	"go.uber.org/zap"
    63  )
    64  
    65  type basicHTTPHandlerTestSuite struct {
    66  	*testServerClient
    67  	server      *Server
    68  	causetstore ekv.CausetStorage
    69  	petri       *petri.Petri
    70  	milevadbdrv *MilevaDBDriver
    71  }
    72  
    73  type HTTPHandlerTestSuite struct {
    74  	*basicHTTPHandlerTestSuite
    75  }
    76  
    77  type HTTPHandlerTestSerialSuite struct {
    78  	*basicHTTPHandlerTestSuite
    79  }
    80  
    81  var _ = Suite(&HTTPHandlerTestSuite{&basicHTTPHandlerTestSuite{}})
    82  
    83  var _ = SerialSuites(&HTTPHandlerTestSerialSuite{&basicHTTPHandlerTestSuite{}})
    84  
    85  func (ts *basicHTTPHandlerTestSuite) SetUpSuite(c *C) {
    86  	ts.testServerClient = newTestServerClient()
    87  }
    88  
    89  func (ts *HTTPHandlerTestSuite) TestRegionIndexRange(c *C) {
    90  	sBlockID := int64(3)
    91  	sIndex := int64(11)
    92  	eBlockID := int64(9)
    93  	recordID := int64(133)
    94  	indexValues := []types.Causet{
    95  		types.NewIntCauset(100),
    96  		types.NewBytesCauset([]byte("foobar")),
    97  		types.NewFloat64Causet(-100.25),
    98  	}
    99  	expectIndexValues := make([]string, 0, len(indexValues))
   100  	for _, v := range indexValues {
   101  		str, err := v.ToString()
   102  		if err != nil {
   103  			str = fmt.Sprintf("%d-%v", v.HoTT(), v.GetValue())
   104  		}
   105  		expectIndexValues = append(expectIndexValues, str)
   106  	}
   107  	encodedValue, err := codec.EncodeKey(&stmtctx.StatementContext{TimeZone: time.Local}, nil, indexValues...)
   108  	c.Assert(err, IsNil)
   109  
   110  	startKey := blockcodec.EncodeIndexSeekKey(sBlockID, sIndex, encodedValue)
   111  	recordPrefix := blockcodec.GenBlockRecordPrefix(eBlockID)
   112  	endKey := blockcodec.EncodeRecordKey(recordPrefix, ekv.IntHandle(recordID))
   113  
   114  	region := &einsteindb.KeyLocation{
   115  		Region:   einsteindb.RegionVerID{},
   116  		StartKey: startKey,
   117  		EndKey:   endKey,
   118  	}
   119  	r, err := helper.NewRegionFrameRange(region)
   120  	c.Assert(err, IsNil)
   121  	c.Assert(r.First.IndexID, Equals, sIndex)
   122  	c.Assert(r.First.IsRecord, IsFalse)
   123  	c.Assert(r.First.RecordID, Equals, int64(0))
   124  	c.Assert(r.First.IndexValues, DeepEquals, expectIndexValues)
   125  	c.Assert(r.Last.RecordID, Equals, recordID)
   126  	c.Assert(r.Last.IndexValues, IsNil)
   127  
   128  	testCases := []struct {
   129  		blockID int64
   130  		indexID int64
   131  		isCover bool
   132  	}{
   133  		{2, 0, false},
   134  		{3, 0, true},
   135  		{9, 0, true},
   136  		{10, 0, false},
   137  		{2, 10, false},
   138  		{3, 10, false},
   139  		{3, 11, true},
   140  		{3, 20, true},
   141  		{9, 10, true},
   142  		{10, 1, false},
   143  	}
   144  	for _, t := range testCases {
   145  		var f *helper.FrameItem
   146  		if t.indexID == 0 {
   147  			f = r.GetRecordFrame(t.blockID, "", "", false)
   148  		} else {
   149  			f = r.GetIndexFrame(t.blockID, t.indexID, "", "", "")
   150  		}
   151  		if t.isCover {
   152  			c.Assert(f, NotNil)
   153  		} else {
   154  			c.Assert(f, IsNil)
   155  		}
   156  	}
   157  }
   158  
   159  func (ts *HTTPHandlerTestSuite) TestRegionCommonHandleRange(c *C) {
   160  	sBlockID := int64(3)
   161  	indexValues := []types.Causet{
   162  		types.NewIntCauset(100),
   163  		types.NewBytesCauset([]byte("foobar")),
   164  		types.NewFloat64Causet(-100.25),
   165  	}
   166  	expectIndexValues := make([]string, 0, len(indexValues))
   167  	for _, v := range indexValues {
   168  		str, err := v.ToString()
   169  		if err != nil {
   170  			str = fmt.Sprintf("%d-%v", v.HoTT(), v.GetValue())
   171  		}
   172  		expectIndexValues = append(expectIndexValues, str)
   173  	}
   174  	encodedValue, err := codec.EncodeKey(&stmtctx.StatementContext{TimeZone: time.Local}, nil, indexValues...)
   175  	c.Assert(err, IsNil)
   176  
   177  	startKey := blockcodec.EncodeRowKey(sBlockID, encodedValue)
   178  
   179  	region := &einsteindb.KeyLocation{
   180  		Region:   einsteindb.RegionVerID{},
   181  		StartKey: startKey,
   182  	}
   183  	r, err := helper.NewRegionFrameRange(region)
   184  	c.Assert(err, IsNil)
   185  	c.Assert(r.First.IsRecord, IsTrue)
   186  	c.Assert(r.First.RecordID, Equals, int64(0))
   187  	c.Assert(r.First.IndexValues, DeepEquals, expectIndexValues)
   188  	c.Assert(r.First.IndexName, Equals, "PRIMARY")
   189  	c.Assert(r.Last.RecordID, Equals, int64(0))
   190  	c.Assert(r.Last.IndexValues, IsNil)
   191  }
   192  
   193  func (ts *HTTPHandlerTestSuite) TestRegionIndexRangeWithEndNoLimit(c *C) {
   194  	sBlockID := int64(15)
   195  	startKey := blockcodec.GenBlockRecordPrefix(sBlockID)
   196  	endKey := []byte("z_aaaaafdfd")
   197  	region := &einsteindb.KeyLocation{
   198  		Region:   einsteindb.RegionVerID{},
   199  		StartKey: startKey,
   200  		EndKey:   endKey,
   201  	}
   202  	r, err := helper.NewRegionFrameRange(region)
   203  	c.Assert(err, IsNil)
   204  	c.Assert(r.First.IsRecord, IsTrue)
   205  	c.Assert(r.Last.IsRecord, IsTrue)
   206  	c.Assert(r.GetRecordFrame(300, "", "", false), NotNil)
   207  	c.Assert(r.GetIndexFrame(200, 100, "", "", ""), NotNil)
   208  }
   209  
   210  func (ts *HTTPHandlerTestSuite) TestRegionIndexRangeWithStartNoLimit(c *C) {
   211  	eBlockID := int64(9)
   212  	startKey := []byte("m_aaaaafdfd")
   213  	endKey := blockcodec.GenBlockRecordPrefix(eBlockID)
   214  	region := &einsteindb.KeyLocation{
   215  		Region:   einsteindb.RegionVerID{},
   216  		StartKey: startKey,
   217  		EndKey:   endKey,
   218  	}
   219  	r, err := helper.NewRegionFrameRange(region)
   220  	c.Assert(err, IsNil)
   221  	c.Assert(r.First.IsRecord, IsFalse)
   222  	c.Assert(r.Last.IsRecord, IsTrue)
   223  	c.Assert(r.GetRecordFrame(3, "", "", false), NotNil)
   224  	c.Assert(r.GetIndexFrame(8, 1, "", "", ""), NotNil)
   225  }
   226  
   227  func (ts *HTTPHandlerTestSuite) TestRegionsAPI(c *C) {
   228  	ts.startServer(c)
   229  	defer ts.stopServer(c)
   230  	ts.prepareData(c)
   231  	resp, err := ts.fetchStatus("/blocks/milevadb/t/regions")
   232  	c.Assert(err, IsNil)
   233  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
   234  	defer resp.Body.Close()
   235  	causetDecoder := json.NewCausetDecoder(resp.Body)
   236  
   237  	var data BlockRegions
   238  	err = causetDecoder.Decode(&data)
   239  	c.Assert(err, IsNil)
   240  	c.Assert(len(data.RecordRegions) > 0, IsTrue)
   241  
   242  	// list region
   243  	for _, region := range data.RecordRegions {
   244  		c.Assert(ts.regionContainsBlock(c, region.ID, data.BlockID), IsTrue)
   245  	}
   246  }
   247  
   248  func (ts *HTTPHandlerTestSuite) TestRegionsAPIForClusterIndex(c *C) {
   249  	ts.startServer(c)
   250  	defer ts.stopServer(c)
   251  	ts.prepareData(c)
   252  	resp, err := ts.fetchStatus("/blocks/milevadb/t/regions")
   253  	c.Assert(err, IsNil)
   254  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
   255  	defer resp.Body.Close()
   256  	causetDecoder := json.NewCausetDecoder(resp.Body)
   257  	var data BlockRegions
   258  	err = causetDecoder.Decode(&data)
   259  	c.Assert(err, IsNil)
   260  	c.Assert(len(data.RecordRegions) > 0, IsTrue)
   261  	// list region
   262  	for _, region := range data.RecordRegions {
   263  		resp, err := ts.fetchStatus(fmt.Sprintf("/regions/%d", region.ID))
   264  		c.Assert(err, IsNil)
   265  		c.Assert(resp.StatusCode, Equals, http.StatusOK)
   266  		causetDecoder := json.NewCausetDecoder(resp.Body)
   267  		var data RegionDetail
   268  		err = causetDecoder.Decode(&data)
   269  		c.Assert(err, IsNil)
   270  		frameCnt := 0
   271  		for _, f := range data.Frames {
   272  			if f.DBName == "milevadb" && f.BlockName == "t" {
   273  				frameCnt++
   274  			}
   275  		}
   276  		// Primary index is as the record frame, so frame count is 1.
   277  		c.Assert(frameCnt, Equals, 1)
   278  		c.Assert(resp.Body.Close(), IsNil)
   279  	}
   280  }
   281  
   282  func (ts *HTTPHandlerTestSuite) regionContainsBlock(c *C, regionID uint64, blockID int64) bool {
   283  	resp, err := ts.fetchStatus(fmt.Sprintf("/regions/%d", regionID))
   284  	c.Assert(err, IsNil)
   285  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
   286  	defer resp.Body.Close()
   287  	causetDecoder := json.NewCausetDecoder(resp.Body)
   288  	var data RegionDetail
   289  	err = causetDecoder.Decode(&data)
   290  	c.Assert(err, IsNil)
   291  	for _, index := range data.Frames {
   292  		if index.BlockID == blockID {
   293  			return true
   294  		}
   295  	}
   296  	return false
   297  }
   298  
   299  func (ts *HTTPHandlerTestSuite) TestListBlockRegions(c *C) {
   300  	ts.startServer(c)
   301  	defer ts.stopServer(c)
   302  	ts.prepareData(c)
   303  	// Test list causet regions with error
   304  	resp, err := ts.fetchStatus("/blocks/fdsfds/aaa/regions")
   305  	c.Assert(err, IsNil)
   306  	defer resp.Body.Close()
   307  	c.Assert(resp.StatusCode, Equals, http.StatusBadRequest)
   308  
   309  	resp, err = ts.fetchStatus("/blocks/milevadb/pt/regions")
   310  	c.Assert(err, IsNil)
   311  	defer resp.Body.Close()
   312  
   313  	var data []*BlockRegions
   314  	dec := json.NewCausetDecoder(resp.Body)
   315  	err = dec.Decode(&data)
   316  	c.Assert(err, IsNil)
   317  
   318  	region := data[1]
   319  	_, err = ts.fetchStatus(fmt.Sprintf("/regions/%d", region.BlockID))
   320  	c.Assert(err, IsNil)
   321  }
   322  
   323  func (ts *HTTPHandlerTestSuite) TestGetRegionByIDWithError(c *C) {
   324  	ts.startServer(c)
   325  	defer ts.stopServer(c)
   326  	resp, err := ts.fetchStatus("/regions/xxx")
   327  	c.Assert(err, IsNil)
   328  	c.Assert(resp.StatusCode, Equals, http.StatusBadRequest)
   329  	defer resp.Body.Close()
   330  }
   331  
   332  func (ts *HTTPHandlerTestSuite) TestBinlogRecover(c *C) {
   333  	ts.startServer(c)
   334  	defer ts.stopServer(c)
   335  	binloginfo.EnableSkipBinlogFlag()
   336  	c.Assert(binloginfo.IsBinlogSkipped(), Equals, true)
   337  	resp, err := ts.fetchStatus("/binlog/recover")
   338  	c.Assert(err, IsNil)
   339  	defer resp.Body.Close()
   340  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
   341  	c.Assert(binloginfo.IsBinlogSkipped(), Equals, false)
   342  
   343  	// Invalid operation will use the default operation.
   344  	binloginfo.EnableSkipBinlogFlag()
   345  	c.Assert(binloginfo.IsBinlogSkipped(), Equals, true)
   346  	resp, err = ts.fetchStatus("/binlog/recover?op=abc")
   347  	c.Assert(err, IsNil)
   348  	defer resp.Body.Close()
   349  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
   350  	c.Assert(binloginfo.IsBinlogSkipped(), Equals, false)
   351  
   352  	binloginfo.EnableSkipBinlogFlag()
   353  	c.Assert(binloginfo.IsBinlogSkipped(), Equals, true)
   354  	resp, err = ts.fetchStatus("/binlog/recover?op=abc&seconds=1")
   355  	c.Assert(err, IsNil)
   356  	defer resp.Body.Close()
   357  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
   358  	c.Assert(binloginfo.IsBinlogSkipped(), Equals, false)
   359  
   360  	binloginfo.EnableSkipBinlogFlag()
   361  	c.Assert(binloginfo.IsBinlogSkipped(), Equals, true)
   362  	binloginfo.AddOneSkippedCommitter()
   363  	resp, err = ts.fetchStatus("/binlog/recover?op=abc&seconds=1")
   364  	c.Assert(err, IsNil)
   365  	defer resp.Body.Close()
   366  	c.Assert(resp.StatusCode, Equals, http.StatusBadRequest)
   367  	c.Assert(binloginfo.IsBinlogSkipped(), Equals, false)
   368  	binloginfo.RemoveOneSkippedCommitter()
   369  
   370  	binloginfo.AddOneSkippedCommitter()
   371  	c.Assert(binloginfo.SkippedCommitterCount(), Equals, int32(1))
   372  	resp, err = ts.fetchStatus("/binlog/recover?op=reset")
   373  	c.Assert(err, IsNil)
   374  	defer resp.Body.Close()
   375  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
   376  	c.Assert(binloginfo.SkippedCommitterCount(), Equals, int32(0))
   377  
   378  	binloginfo.EnableSkipBinlogFlag()
   379  	resp, err = ts.fetchStatus("/binlog/recover?op=nowait")
   380  	c.Assert(err, IsNil)
   381  	defer resp.Body.Close()
   382  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
   383  	c.Assert(binloginfo.IsBinlogSkipped(), Equals, false)
   384  
   385  	// Only the first should work.
   386  	binloginfo.EnableSkipBinlogFlag()
   387  	resp, err = ts.fetchStatus("/binlog/recover?op=nowait&op=reset")
   388  	c.Assert(err, IsNil)
   389  	defer resp.Body.Close()
   390  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
   391  	c.Assert(binloginfo.IsBinlogSkipped(), Equals, false)
   392  
   393  	resp, err = ts.fetchStatus("/binlog/recover?op=status")
   394  	c.Assert(err, IsNil)
   395  	defer resp.Body.Close()
   396  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
   397  }
   398  
   399  func (ts *HTTPHandlerTestSuite) TestRegionsFromMeta(c *C) {
   400  	ts.startServer(c)
   401  	defer ts.stopServer(c)
   402  	resp, err := ts.fetchStatus("/regions/spacetime")
   403  	c.Assert(err, IsNil)
   404  	defer resp.Body.Close()
   405  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
   406  
   407  	// Verify the resp body.
   408  	causetDecoder := json.NewCausetDecoder(resp.Body)
   409  	spacetimes := make([]RegionMeta, 0)
   410  	err = causetDecoder.Decode(&spacetimes)
   411  	c.Assert(err, IsNil)
   412  	for _, spacetime := range spacetimes {
   413  		c.Assert(spacetime.ID != 0, IsTrue)
   414  	}
   415  
   416  	// test no panic
   417  	c.Assert(failpoint.Enable("github.com/whtcorpsinc/milevadb/server/errGetRegionByIDEmpty", `return(true)`), IsNil)
   418  	resp1, err := ts.fetchStatus("/regions/spacetime")
   419  	c.Assert(err, IsNil)
   420  	defer resp1.Body.Close()
   421  	c.Assert(failpoint.Disable("github.com/whtcorpsinc/milevadb/server/errGetRegionByIDEmpty"), IsNil)
   422  }
   423  
   424  func (ts *basicHTTPHandlerTestSuite) startServer(c *C) {
   425  	var err error
   426  	ts.causetstore, err = mockstore.NewMockStore()
   427  	c.Assert(err, IsNil)
   428  	ts.petri, err = stochastik.BootstrapStochastik(ts.causetstore)
   429  	c.Assert(err, IsNil)
   430  	ts.milevadbdrv = NewMilevaDBDriver(ts.causetstore)
   431  
   432  	cfg := newTestConfig()
   433  	cfg.CausetStore = "einsteindb"
   434  	cfg.Port = 0
   435  	cfg.Status.StatusPort = 0
   436  	cfg.Status.ReportStatus = true
   437  
   438  	server, err := NewServer(cfg, ts.milevadbdrv)
   439  	c.Assert(err, IsNil)
   440  	ts.port = getPortFromTCPAddr(server.listener.Addr())
   441  	ts.statusPort = getPortFromTCPAddr(server.statusListener.Addr())
   442  	ts.server = server
   443  	go server.Run()
   444  	ts.waitUntilServerOnline()
   445  }
   446  
   447  func getPortFromTCPAddr(addr net.Addr) uint {
   448  	return uint(addr.(*net.TCPAddr).Port)
   449  }
   450  
   451  func (ts *basicHTTPHandlerTestSuite) stopServer(c *C) {
   452  	if ts.petri != nil {
   453  		ts.petri.Close()
   454  	}
   455  	if ts.causetstore != nil {
   456  		ts.causetstore.Close()
   457  	}
   458  	if ts.server != nil {
   459  		ts.server.Close()
   460  	}
   461  }
   462  
   463  func (ts *basicHTTPHandlerTestSuite) prepareData(c *C) {
   464  	EDB, err := allegrosql.Open("allegrosql", ts.getDSN())
   465  	c.Assert(err, IsNil, Commentf("Error connecting"))
   466  	defer EDB.Close()
   467  	dbt := &DBTest{c, EDB}
   468  
   469  	dbt.mustInterDirc("create database milevadb;")
   470  	dbt.mustInterDirc("use milevadb;")
   471  	dbt.mustInterDirc("create causet milevadb.test (a int auto_increment primary key, b varchar(20));")
   472  	dbt.mustInterDirc("insert milevadb.test values (1, 1);")
   473  	txn1, err := dbt.EDB.Begin()
   474  	c.Assert(err, IsNil)
   475  	_, err = txn1.InterDirc("uFIDelate milevadb.test set b = b + 1 where a = 1;")
   476  	c.Assert(err, IsNil)
   477  	_, err = txn1.InterDirc("insert milevadb.test values (2, 2);")
   478  	c.Assert(err, IsNil)
   479  	_, err = txn1.InterDirc("insert milevadb.test (a) values (3);")
   480  	c.Assert(err, IsNil)
   481  	_, err = txn1.InterDirc("insert milevadb.test values (4, '');")
   482  	c.Assert(err, IsNil)
   483  	err = txn1.Commit()
   484  	c.Assert(err, IsNil)
   485  	dbt.mustInterDirc("alter causet milevadb.test add index idx1 (a, b);")
   486  	dbt.mustInterDirc("alter causet milevadb.test add unique index idx2 (a, b);")
   487  
   488  	dbt.mustInterDirc(`create causet milevadb.pt (a int primary key, b varchar(20), key idx(a, b))
   489  partition by range (a)
   490  (partition p0 values less than (256),
   491   partition p1 values less than (512),
   492   partition p2 values less than (1024))`)
   493  
   494  	txn2, err := dbt.EDB.Begin()
   495  	c.Assert(err, IsNil)
   496  	txn2.InterDirc("insert into milevadb.pt values (42, '123')")
   497  	txn2.InterDirc("insert into milevadb.pt values (256, 'b')")
   498  	txn2.InterDirc("insert into milevadb.pt values (666, 'def')")
   499  	err = txn2.Commit()
   500  	c.Assert(err, IsNil)
   501  
   502  	dbt.mustInterDirc("set @@milevadb_enable_clustered_index = 1")
   503  	dbt.mustInterDirc("drop causet if exists t")
   504  	dbt.mustInterDirc("create causet t (a double, b varchar(20), c int, primary key(a,b))")
   505  	dbt.mustInterDirc("insert into t values(1.1,'111',1),(2.2,'222',2)")
   506  }
   507  
   508  func decodeKeyMvcc(closer io.ReadCloser, c *C, valid bool) {
   509  	causetDecoder := json.NewCausetDecoder(closer)
   510  	var data mvccKV
   511  	err := causetDecoder.Decode(&data)
   512  	c.Assert(err, IsNil)
   513  	if valid {
   514  		c.Assert(data.Value.Info, NotNil)
   515  		c.Assert(len(data.Value.Info.Writes), Greater, 0)
   516  	} else {
   517  		c.Assert(data.Value.Info.Lock, IsNil)
   518  		c.Assert(data.Value.Info.Writes, IsNil)
   519  		c.Assert(data.Value.Info.Values, IsNil)
   520  	}
   521  }
   522  
   523  func (ts *HTTPHandlerTestSuite) TestGetBlockMVCC(c *C) {
   524  	ts.startServer(c)
   525  	ts.prepareData(c)
   526  	defer ts.stopServer(c)
   527  
   528  	resp, err := ts.fetchStatus(fmt.Sprintf("/mvcc/key/milevadb/test/1"))
   529  	c.Assert(err, IsNil)
   530  	causetDecoder := json.NewCausetDecoder(resp.Body)
   531  	var data mvccKV
   532  	err = causetDecoder.Decode(&data)
   533  	c.Assert(err, IsNil)
   534  	c.Assert(data.Value, NotNil)
   535  	info := data.Value.Info
   536  	c.Assert(info, NotNil)
   537  	c.Assert(len(info.Writes), Greater, 0)
   538  
   539  	// TODO: EntangledStore will not return Op_Lock.
   540  	// Use this workaround to support two backend, we can remove this replog after deprecated mockeinsteindb.
   541  	var startTs uint64
   542  	for _, w := range info.Writes {
   543  		if w.Type == ekvrpcpb.Op_Lock {
   544  			continue
   545  		}
   546  		startTs = w.StartTs
   547  		break
   548  	}
   549  
   550  	resp, err = ts.fetchStatus(fmt.Sprintf("/mvcc/txn/%d/milevadb/test", startTs))
   551  	c.Assert(err, IsNil)
   552  	var p2 mvccKV
   553  	causetDecoder = json.NewCausetDecoder(resp.Body)
   554  	err = causetDecoder.Decode(&p2)
   555  	c.Assert(err, IsNil)
   556  
   557  	for i, expect := range info.Values {
   558  		v2 := p2.Value.Info.Values[i].Value
   559  		c.Assert(v2, BytesEquals, expect.Value)
   560  	}
   561  
   562  	hexKey := p2.Key
   563  	resp, err = ts.fetchStatus("/mvcc/hex/" + hexKey)
   564  	c.Assert(err, IsNil)
   565  	causetDecoder = json.NewCausetDecoder(resp.Body)
   566  	var data2 mvccKV
   567  	err = causetDecoder.Decode(&data2)
   568  	c.Assert(err, IsNil)
   569  	c.Assert(data2, DeepEquals, data)
   570  
   571  	resp, err = ts.fetchStatus(fmt.Sprintf("/mvcc/key/milevadb/test/1?decode=true"))
   572  	c.Assert(err, IsNil)
   573  	causetDecoder = json.NewCausetDecoder(resp.Body)
   574  	var data3 map[string]interface{}
   575  	err = causetDecoder.Decode(&data3)
   576  	c.Assert(err, IsNil)
   577  	c.Assert(data3["key"], NotNil)
   578  	c.Assert(data3["info"], NotNil)
   579  	c.Assert(data3["data"], NotNil)
   580  	c.Assert(data3["decode_error"], IsNil)
   581  
   582  	resp, err = ts.fetchStatus("/mvcc/key/milevadb/pt(p0)/42?decode=true")
   583  	c.Assert(err, IsNil)
   584  	defer resp.Body.Close()
   585  	causetDecoder = json.NewCausetDecoder(resp.Body)
   586  	var data4 map[string]interface{}
   587  	err = causetDecoder.Decode(&data4)
   588  	c.Assert(err, IsNil)
   589  	c.Assert(data4["key"], NotNil)
   590  	c.Assert(data4["info"], NotNil)
   591  	c.Assert(data4["data"], NotNil)
   592  	c.Assert(data4["decode_error"], IsNil)
   593  }
   594  
   595  func (ts *HTTPHandlerTestSuite) TestGetMVCCNotFound(c *C) {
   596  	ts.startServer(c)
   597  	ts.prepareData(c)
   598  	defer ts.stopServer(c)
   599  	resp, err := ts.fetchStatus(fmt.Sprintf("/mvcc/key/milevadb/test/1234"))
   600  	c.Assert(err, IsNil)
   601  	causetDecoder := json.NewCausetDecoder(resp.Body)
   602  	var data mvccKV
   603  	err = causetDecoder.Decode(&data)
   604  	c.Assert(err, IsNil)
   605  	c.Assert(data.Value.Info.Lock, IsNil)
   606  	c.Assert(data.Value.Info.Writes, IsNil)
   607  	c.Assert(data.Value.Info.Values, IsNil)
   608  }
   609  
   610  func (ts *HTTPHandlerTestSuite) TestTiFlashReplica(c *C) {
   611  	ts.startServer(c)
   612  	ts.prepareData(c)
   613  	defer ts.stopServer(c)
   614  
   615  	EDB, err := allegrosql.Open("allegrosql", ts.getDSN())
   616  	c.Assert(err, IsNil, Commentf("Error connecting"))
   617  	defer EDB.Close()
   618  	dbt := &DBTest{c, EDB}
   619  
   620  	defer func(originGC bool) {
   621  		if originGC {
   622  			dbs.EmulatorGCEnable()
   623  		} else {
   624  			dbs.EmulatorGCDisable()
   625  		}
   626  	}(dbs.IsEmulatorGCEnable())
   627  
   628  	// Disable emulator GC.
   629  	// Otherwise emulator GC will delete causet record as soon as possible after execute drop causet DBS.
   630  	dbs.EmulatorGCDisable()
   631  	gcTimeFormat := "20060102-15:04:05 -0700 MST"
   632  	timeBeforeDrop := time.Now().Add(0 - 48*60*60*time.Second).Format(gcTimeFormat)
   633  	safePointALLEGROSQL := `INSERT HIGH_PRIORITY INTO allegrosql.milevadb VALUES ('einsteindb_gc_safe_point', '%[1]s', ''),('einsteindb_gc_enable','true','')
   634  			       ON DUPLICATE KEY
   635  			       UFIDelATE variable_value = '%[1]s'`
   636  	// Set GC safe point and enable GC.
   637  	dbt.mustInterDirc(fmt.Sprintf(safePointALLEGROSQL, timeBeforeDrop))
   638  
   639  	resp, err := ts.fetchStatus("/tiflash/replica")
   640  	c.Assert(err, IsNil)
   641  	causetDecoder := json.NewCausetDecoder(resp.Body)
   642  	var data []blockFlashReplicaInfo
   643  	err = causetDecoder.Decode(&data)
   644  	c.Assert(err, IsNil)
   645  	c.Assert(len(data), Equals, 0)
   646  
   647  	c.Assert(failpoint.Enable("github.com/whtcorpsinc/milevadb/schemareplicant/mockTiFlashStoreCount", `return(true)`), IsNil)
   648  	defer failpoint.Disable("github.com/whtcorpsinc/milevadb/schemareplicant/mockTiFlashStoreCount")
   649  	dbt.mustInterDirc("use milevadb")
   650  	dbt.mustInterDirc("alter causet test set tiflash replica 2 location labels 'a','b';")
   651  
   652  	resp, err = ts.fetchStatus("/tiflash/replica")
   653  	c.Assert(err, IsNil)
   654  	causetDecoder = json.NewCausetDecoder(resp.Body)
   655  	err = causetDecoder.Decode(&data)
   656  	c.Assert(err, IsNil)
   657  	c.Assert(len(data), Equals, 1)
   658  	c.Assert(data[0].ReplicaCount, Equals, uint64(2))
   659  	c.Assert(strings.Join(data[0].LocationLabels, ","), Equals, "a,b")
   660  	c.Assert(data[0].Available, Equals, false)
   661  
   662  	resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(`{"id":84,"region_count":3,"flash_region_count":3}`)))
   663  	c.Assert(err, IsNil)
   664  	c.Assert(resp, NotNil)
   665  	body, err := ioutil.ReadAll(resp.Body)
   666  	c.Assert(err, IsNil)
   667  	c.Assert(string(body), Equals, "[schemaReplicant:1146]Block which ID = 84 does not exist.")
   668  
   669  	t, err := ts.petri.SchemaReplicant().BlockByName(perceptron.NewCIStr("milevadb"), perceptron.NewCIStr("test"))
   670  	c.Assert(err, IsNil)
   671  	req := fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, t.Meta().ID)
   672  	resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req)))
   673  	c.Assert(err, IsNil)
   674  	c.Assert(resp, NotNil)
   675  	body, err = ioutil.ReadAll(resp.Body)
   676  	c.Assert(err, IsNil)
   677  	c.Assert(string(body), Equals, "")
   678  
   679  	resp, err = ts.fetchStatus("/tiflash/replica")
   680  	c.Assert(err, IsNil)
   681  	causetDecoder = json.NewCausetDecoder(resp.Body)
   682  	err = causetDecoder.Decode(&data)
   683  	c.Assert(err, IsNil)
   684  	resp.Body.Close()
   685  	c.Assert(len(data), Equals, 1)
   686  	c.Assert(data[0].ReplicaCount, Equals, uint64(2))
   687  	c.Assert(strings.Join(data[0].LocationLabels, ","), Equals, "a,b")
   688  	c.Assert(data[0].Available, Equals, true) // The status should be true now.
   689  
   690  	// Should not take effect.
   691  	dbt.mustInterDirc("alter causet test set tiflash replica 2 location labels 'a','b';")
   692  	checkFunc := func() {
   693  		resp, err = ts.fetchStatus("/tiflash/replica")
   694  		c.Assert(err, IsNil)
   695  		causetDecoder = json.NewCausetDecoder(resp.Body)
   696  		err = causetDecoder.Decode(&data)
   697  		c.Assert(err, IsNil)
   698  		resp.Body.Close()
   699  		c.Assert(len(data), Equals, 1)
   700  		c.Assert(data[0].ReplicaCount, Equals, uint64(2))
   701  		c.Assert(strings.Join(data[0].LocationLabels, ","), Equals, "a,b")
   702  		c.Assert(data[0].Available, Equals, true) // The status should be true now.
   703  	}
   704  
   705  	// Test for get dropped causet tiflash replica info.
   706  	dbt.mustInterDirc("drop causet test")
   707  	checkFunc()
   708  
   709  	// Test unique causet id replica info.
   710  	dbt.mustInterDirc("flashback causet test")
   711  	checkFunc()
   712  	dbt.mustInterDirc("drop causet test")
   713  	checkFunc()
   714  	dbt.mustInterDirc("flashback causet test")
   715  	checkFunc()
   716  
   717  	// Test for partition causet.
   718  	dbt.mustInterDirc("alter causet pt set tiflash replica 2 location labels 'a','b';")
   719  	dbt.mustInterDirc("alter causet test set tiflash replica 0;")
   720  	resp, err = ts.fetchStatus("/tiflash/replica")
   721  	c.Assert(err, IsNil)
   722  	causetDecoder = json.NewCausetDecoder(resp.Body)
   723  	err = causetDecoder.Decode(&data)
   724  	c.Assert(err, IsNil)
   725  	resp.Body.Close()
   726  	c.Assert(len(data), Equals, 3)
   727  	c.Assert(data[0].ReplicaCount, Equals, uint64(2))
   728  	c.Assert(strings.Join(data[0].LocationLabels, ","), Equals, "a,b")
   729  	c.Assert(data[0].Available, Equals, false)
   730  
   731  	pid0 := data[0].ID
   732  	pid1 := data[1].ID
   733  	pid2 := data[2].ID
   734  
   735  	// Mock for partition 1 replica was available.
   736  	req = fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, pid1)
   737  	resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req)))
   738  	c.Assert(err, IsNil)
   739  	resp.Body.Close()
   740  	resp, err = ts.fetchStatus("/tiflash/replica")
   741  	c.Assert(err, IsNil)
   742  	causetDecoder = json.NewCausetDecoder(resp.Body)
   743  	err = causetDecoder.Decode(&data)
   744  	c.Assert(err, IsNil)
   745  	resp.Body.Close()
   746  	c.Assert(len(data), Equals, 3)
   747  	c.Assert(data[0].Available, Equals, false)
   748  	c.Assert(data[1].Available, Equals, true)
   749  	c.Assert(data[2].Available, Equals, false)
   750  
   751  	// Mock for partition 0,2 replica was available.
   752  	req = fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, pid0)
   753  	resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req)))
   754  	c.Assert(err, IsNil)
   755  	resp.Body.Close()
   756  	req = fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, pid2)
   757  	resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req)))
   758  	c.Assert(err, IsNil)
   759  	resp.Body.Close()
   760  	checkFunc = func() {
   761  		resp, err = ts.fetchStatus("/tiflash/replica")
   762  		c.Assert(err, IsNil)
   763  		causetDecoder = json.NewCausetDecoder(resp.Body)
   764  		err = causetDecoder.Decode(&data)
   765  		c.Assert(err, IsNil)
   766  		resp.Body.Close()
   767  		c.Assert(len(data), Equals, 3)
   768  		c.Assert(data[0].Available, Equals, true)
   769  		c.Assert(data[1].Available, Equals, true)
   770  		c.Assert(data[2].Available, Equals, true)
   771  	}
   772  
   773  	// Test for get truncated causet tiflash replica info.
   774  	dbt.mustInterDirc("truncate causet pt")
   775  	dbt.mustInterDirc("alter causet pt set tiflash replica 0;")
   776  	checkFunc()
   777  }
   778  
   779  func (ts *HTTPHandlerTestSuite) TestDecodeDeferredCausetValue(c *C) {
   780  	ts.startServer(c)
   781  	ts.prepareData(c)
   782  	defer ts.stopServer(c)
   783  
   784  	// defCausumn is a structure used for test
   785  	type defCausumn struct {
   786  		id int64
   787  		tp *types.FieldType
   788  	}
   789  	// Backfill defCausumns.
   790  	c1 := &defCausumn{id: 1, tp: types.NewFieldType(allegrosql.TypeLonglong)}
   791  	c2 := &defCausumn{id: 2, tp: types.NewFieldType(allegrosql.TypeVarchar)}
   792  	c3 := &defCausumn{id: 3, tp: types.NewFieldType(allegrosql.TypeNewDecimal)}
   793  	c4 := &defCausumn{id: 4, tp: types.NewFieldType(allegrosql.TypeTimestamp)}
   794  	defcaus := []*defCausumn{c1, c2, c3, c4}
   795  	event := make([]types.Causet, len(defcaus))
   796  	event[0] = types.NewIntCauset(100)
   797  	event[1] = types.NewBytesCauset([]byte("abc"))
   798  	event[2] = types.NewDecimalCauset(types.NewDecFromInt(1))
   799  	event[3] = types.NewTimeCauset(types.NewTime(types.FromGoTime(time.Now()), allegrosql.TypeTimestamp, 6))
   800  
   801  	// Encode the event.
   802  	defCausIDs := make([]int64, 0, 3)
   803  	for _, defCaus := range defcaus {
   804  		defCausIDs = append(defCausIDs, defCaus.id)
   805  	}
   806  	rd := rowcodec.CausetEncoder{Enable: true}
   807  	sc := &stmtctx.StatementContext{TimeZone: time.UTC}
   808  	bs, err := blockcodec.EncodeRow(sc, event, defCausIDs, nil, nil, &rd)
   809  	c.Assert(err, IsNil)
   810  	c.Assert(bs, NotNil)
   811  	bin := base64.StdEncoding.EncodeToString(bs)
   812  
   813  	unitTest := func(defCaus *defCausumn) {
   814  		path := fmt.Sprintf("/blocks/%d/%v/%d/%d?rowBin=%s", defCaus.id, defCaus.tp.Tp, defCaus.tp.Flag, defCaus.tp.Flen, bin)
   815  		resp, err := ts.fetchStatus(path)
   816  		c.Assert(err, IsNil, Commentf("url:%s", ts.statusURL(path)))
   817  		causetDecoder := json.NewCausetDecoder(resp.Body)
   818  		var data interface{}
   819  		err = causetDecoder.Decode(&data)
   820  		c.Assert(err, IsNil, Commentf("url:%v\ndata%v", ts.statusURL(path), data))
   821  		defCausVal, err := types.CausetsToString([]types.Causet{event[defCaus.id-1]}, false)
   822  		c.Assert(err, IsNil)
   823  		c.Assert(data, Equals, defCausVal, Commentf("url:%v", ts.statusURL(path)))
   824  	}
   825  
   826  	for _, defCaus := range defcaus {
   827  		unitTest(defCaus)
   828  	}
   829  
   830  	// Test bin has `+`.
   831  	// 2020-03-08 16:01:00.315313
   832  	bin = "CAIIyAEIBAIGYWJjCAYGAQCBCAgJsZ+TgISg1M8Z"
   833  	event[3] = types.NewTimeCauset(types.NewTime(types.FromGoTime(time.Date(2020, 3, 8, 16, 1, 0, 315313000, time.UTC)), allegrosql.TypeTimestamp, 6))
   834  	unitTest(defcaus[3])
   835  
   836  	// Test bin has `/`.
   837  	// 2020-03-08 02:44:46.409199
   838  	bin = "CAIIyAEIBAIGYWJjCAYGAQCBCAgJ7/yY8LKF1M8Z"
   839  	event[3] = types.NewTimeCauset(types.NewTime(types.FromGoTime(time.Date(2020, 3, 8, 2, 44, 46, 409199000, time.UTC)), allegrosql.TypeTimestamp, 6))
   840  	unitTest(defcaus[3])
   841  }
   842  
   843  func (ts *HTTPHandlerTestSuite) TestGetIndexMVCC(c *C) {
   844  	ts.startServer(c)
   845  	ts.prepareData(c)
   846  	defer ts.stopServer(c)
   847  
   848  	// tests for normal index key
   849  	resp, err := ts.fetchStatus("/mvcc/index/milevadb/test/idx1/1?a=1&b=2")
   850  	c.Assert(err, IsNil)
   851  	decodeKeyMvcc(resp.Body, c, true)
   852  
   853  	resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx2/1?a=1&b=2")
   854  	c.Assert(err, IsNil)
   855  	decodeKeyMvcc(resp.Body, c, true)
   856  
   857  	// tests for index key which includes null
   858  	resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx1/3?a=3&b")
   859  	c.Assert(err, IsNil)
   860  	decodeKeyMvcc(resp.Body, c, true)
   861  
   862  	resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx2/3?a=3&b")
   863  	c.Assert(err, IsNil)
   864  	decodeKeyMvcc(resp.Body, c, true)
   865  
   866  	// tests for index key which includes empty string
   867  	resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx1/4?a=4&b=")
   868  	c.Assert(err, IsNil)
   869  	decodeKeyMvcc(resp.Body, c, true)
   870  
   871  	resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx2/3?a=4&b=")
   872  	c.Assert(err, IsNil)
   873  	decodeKeyMvcc(resp.Body, c, true)
   874  
   875  	// tests for wrong key
   876  	resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx1/5?a=5&b=1")
   877  	c.Assert(err, IsNil)
   878  	decodeKeyMvcc(resp.Body, c, false)
   879  
   880  	resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx2/5?a=5&b=1")
   881  	c.Assert(err, IsNil)
   882  	decodeKeyMvcc(resp.Body, c, false)
   883  
   884  	// tests for missing defCausumn value
   885  	resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx1/1?a=1")
   886  	c.Assert(err, IsNil)
   887  	causetDecoder := json.NewCausetDecoder(resp.Body)
   888  	var data1 mvccKV
   889  	err = causetDecoder.Decode(&data1)
   890  	c.Assert(err, NotNil)
   891  
   892  	resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx2/1?a=1")
   893  	c.Assert(err, IsNil)
   894  	causetDecoder = json.NewCausetDecoder(resp.Body)
   895  	var data2 mvccKV
   896  	err = causetDecoder.Decode(&data2)
   897  	c.Assert(err, NotNil)
   898  
   899  	resp, err = ts.fetchStatus("/mvcc/index/milevadb/pt(p2)/idx/666?a=666&b=def")
   900  	c.Assert(err, IsNil)
   901  	defer resp.Body.Close()
   902  	decodeKeyMvcc(resp.Body, c, true)
   903  }
   904  
   905  func (ts *HTTPHandlerTestSuite) TestGetSettings(c *C) {
   906  	ts.startServer(c)
   907  	ts.prepareData(c)
   908  	defer ts.stopServer(c)
   909  	resp, err := ts.fetchStatus("/settings")
   910  	c.Assert(err, IsNil)
   911  	causetDecoder := json.NewCausetDecoder(resp.Body)
   912  	var settings *config.Config
   913  	err = causetDecoder.Decode(&settings)
   914  	c.Assert(err, IsNil)
   915  	c.Assert(settings, DeepEquals, config.GetGlobalConfig())
   916  }
   917  
   918  func (ts *HTTPHandlerTestSuite) TestGetSchema(c *C) {
   919  	ts.startServer(c)
   920  	ts.prepareData(c)
   921  	defer ts.stopServer(c)
   922  	resp, err := ts.fetchStatus("/schemaReplicant")
   923  	c.Assert(err, IsNil)
   924  	causetDecoder := json.NewCausetDecoder(resp.Body)
   925  	var dbs []*perceptron.DBInfo
   926  	err = causetDecoder.Decode(&dbs)
   927  	c.Assert(err, IsNil)
   928  	expects := []string{"information_schema", "metrics_schema", "allegrosql", "performance_schema", "test", "milevadb"}
   929  	names := make([]string, len(dbs))
   930  	for i, v := range dbs {
   931  		names[i] = v.Name.L
   932  	}
   933  	sort.Strings(names)
   934  	c.Assert(names, DeepEquals, expects)
   935  
   936  	resp, err = ts.fetchStatus("/schemaReplicant?block_id=5")
   937  	c.Assert(err, IsNil)
   938  	var t *perceptron.BlockInfo
   939  	causetDecoder = json.NewCausetDecoder(resp.Body)
   940  	err = causetDecoder.Decode(&t)
   941  	c.Assert(err, IsNil)
   942  	c.Assert(t.Name.L, Equals, "user")
   943  
   944  	_, err = ts.fetchStatus("/schemaReplicant?block_id=a")
   945  	c.Assert(err, IsNil)
   946  
   947  	_, err = ts.fetchStatus("/schemaReplicant?block_id=1")
   948  	c.Assert(err, IsNil)
   949  
   950  	_, err = ts.fetchStatus("/schemaReplicant?block_id=-1")
   951  	c.Assert(err, IsNil)
   952  
   953  	resp, err = ts.fetchStatus("/schemaReplicant/milevadb")
   954  	c.Assert(err, IsNil)
   955  	var lt []*perceptron.BlockInfo
   956  	causetDecoder = json.NewCausetDecoder(resp.Body)
   957  	err = causetDecoder.Decode(&lt)
   958  	c.Assert(err, IsNil)
   959  	c.Assert(len(lt), Greater, 0)
   960  
   961  	_, err = ts.fetchStatus("/schemaReplicant/abc")
   962  	c.Assert(err, IsNil)
   963  
   964  	resp, err = ts.fetchStatus("/schemaReplicant/milevadb/test")
   965  	c.Assert(err, IsNil)
   966  	causetDecoder = json.NewCausetDecoder(resp.Body)
   967  	err = causetDecoder.Decode(&t)
   968  	c.Assert(err, IsNil)
   969  	c.Assert(t.Name.L, Equals, "test")
   970  
   971  	_, err = ts.fetchStatus("/schemaReplicant/milevadb/abc")
   972  	c.Assert(err, IsNil)
   973  
   974  	resp, err = ts.fetchStatus("/EDB-causet/5")
   975  	c.Assert(err, IsNil)
   976  	var dbtbl *dbBlockInfo
   977  	causetDecoder = json.NewCausetDecoder(resp.Body)
   978  	err = causetDecoder.Decode(&dbtbl)
   979  	c.Assert(err, IsNil)
   980  	c.Assert(dbtbl.BlockInfo.Name.L, Equals, "user")
   981  	c.Assert(dbtbl.DBInfo.Name.L, Equals, "allegrosql")
   982  	se, err := stochastik.CreateStochastik(ts.causetstore.(ekv.CausetStorage))
   983  	c.Assert(err, IsNil)
   984  	c.Assert(dbtbl.SchemaVersion, Equals, petri.GetPetri(se.(stochastikctx.Context)).SchemaReplicant().SchemaMetaVersion())
   985  
   986  	EDB, err := allegrosql.Open("allegrosql", ts.getDSN())
   987  	c.Assert(err, IsNil, Commentf("Error connecting"))
   988  	defer EDB.Close()
   989  	dbt := &DBTest{c, EDB}
   990  
   991  	dbt.mustInterDirc("create database if not exists test;")
   992  	dbt.mustInterDirc("use test;")
   993  	dbt.mustInterDirc(` create causet t1 (id int KEY)
   994  		partition by range (id) (
   995  		PARTITION p0 VALUES LESS THAN (3),
   996  		PARTITION p1 VALUES LESS THAN (5),
   997  		PARTITION p2 VALUES LESS THAN (7),
   998  		PARTITION p3 VALUES LESS THAN (9))`)
   999  
  1000  	resp, err = ts.fetchStatus("/schemaReplicant/test/t1")
  1001  	c.Assert(err, IsNil)
  1002  	causetDecoder = json.NewCausetDecoder(resp.Body)
  1003  	err = causetDecoder.Decode(&t)
  1004  	c.Assert(err, IsNil)
  1005  	c.Assert(t.Name.L, Equals, "t1")
  1006  
  1007  	resp, err = ts.fetchStatus(fmt.Sprintf("/EDB-causet/%v", t.GetPartitionInfo().Definitions[0].ID))
  1008  	c.Assert(err, IsNil)
  1009  	causetDecoder = json.NewCausetDecoder(resp.Body)
  1010  	err = causetDecoder.Decode(&dbtbl)
  1011  	c.Assert(err, IsNil)
  1012  	c.Assert(dbtbl.BlockInfo.Name.L, Equals, "t1")
  1013  	c.Assert(dbtbl.DBInfo.Name.L, Equals, "test")
  1014  	c.Assert(dbtbl.BlockInfo, DeepEquals, t)
  1015  }
  1016  
  1017  func (ts *HTTPHandlerTestSuite) TestAllHistory(c *C) {
  1018  	ts.startServer(c)
  1019  	ts.prepareData(c)
  1020  	defer ts.stopServer(c)
  1021  	_, err := ts.fetchStatus("/dbs/history/?limit=3")
  1022  	c.Assert(err, IsNil)
  1023  	_, err = ts.fetchStatus("/dbs/history/?limit=-1")
  1024  	c.Assert(err, IsNil)
  1025  
  1026  	resp, err := ts.fetchStatus("/dbs/history")
  1027  	c.Assert(err, IsNil)
  1028  	causetDecoder := json.NewCausetDecoder(resp.Body)
  1029  
  1030  	var jobs []*perceptron.Job
  1031  	s, _ := stochastik.CreateStochastik(ts.server.newEinsteinDBHandlerTool().CausetStore.(ekv.CausetStorage))
  1032  	defer s.Close()
  1033  	causetstore := petri.GetPetri(s.(stochastikctx.Context)).CausetStore()
  1034  	txn, _ := causetstore.Begin()
  1035  	txnMeta := spacetime.NewMeta(txn)
  1036  	txnMeta.GetAllHistoryDBSJobs()
  1037  	data, _ := txnMeta.GetAllHistoryDBSJobs()
  1038  	err = causetDecoder.Decode(&jobs)
  1039  
  1040  	c.Assert(err, IsNil)
  1041  	c.Assert(jobs, DeepEquals, data)
  1042  }
  1043  
  1044  func (ts *HTTPHandlerTestSuite) TestPostSettings(c *C) {
  1045  	ts.startServer(c)
  1046  	ts.prepareData(c)
  1047  	defer ts.stopServer(c)
  1048  	form := make(url.Values)
  1049  	form.Set("log_level", "error")
  1050  	form.Set("milevadb_general_log", "1")
  1051  	resp, err := ts.formStatus("/settings", form)
  1052  	c.Assert(err, IsNil)
  1053  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
  1054  	c.Assert(log.GetLevel(), Equals, log.ErrorLevel)
  1055  	c.Assert(zaplog.GetLevel(), Equals, zap.ErrorLevel)
  1056  	c.Assert(config.GetGlobalConfig().Log.Level, Equals, "error")
  1057  	c.Assert(atomic.LoadUint32(&variable.ProcessGeneralLog), Equals, uint32(1))
  1058  	form = make(url.Values)
  1059  	form.Set("log_level", "fatal")
  1060  	form.Set("milevadb_general_log", "0")
  1061  	resp, err = ts.formStatus("/settings", form)
  1062  	c.Assert(err, IsNil)
  1063  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
  1064  	c.Assert(atomic.LoadUint32(&variable.ProcessGeneralLog), Equals, uint32(0))
  1065  	c.Assert(log.GetLevel(), Equals, log.FatalLevel)
  1066  	c.Assert(zaplog.GetLevel(), Equals, zap.FatalLevel)
  1067  	c.Assert(config.GetGlobalConfig().Log.Level, Equals, "fatal")
  1068  	form.Set("log_level", os.Getenv("log_level"))
  1069  
  1070  	// test dbs_slow_threshold
  1071  	form = make(url.Values)
  1072  	form.Set("dbs_slow_threshold", "200")
  1073  	resp, err = ts.formStatus("/settings", form)
  1074  	c.Assert(err, IsNil)
  1075  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
  1076  	c.Assert(atomic.LoadUint32(&variable.DBSSlowOprThreshold), Equals, uint32(200))
  1077  
  1078  	// test check_mb4_value_in_utf8
  1079  	EDB, err := allegrosql.Open("allegrosql", ts.getDSN())
  1080  	c.Assert(err, IsNil, Commentf("Error connecting"))
  1081  	defer EDB.Close()
  1082  	dbt := &DBTest{c, EDB}
  1083  
  1084  	dbt.mustInterDirc("create database milevadb_test;")
  1085  	dbt.mustInterDirc("use milevadb_test;")
  1086  	dbt.mustInterDirc("drop causet if exists t2;")
  1087  	dbt.mustInterDirc("create causet t2(a varchar(100) charset utf8);")
  1088  	form.Set("check_mb4_value_in_utf8", "1")
  1089  	resp, err = ts.formStatus("/settings", form)
  1090  	c.Assert(err, IsNil)
  1091  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
  1092  	c.Assert(config.GetGlobalConfig().CheckMb4ValueInUTF8, Equals, true)
  1093  	txn1, err := dbt.EDB.Begin()
  1094  	c.Assert(err, IsNil)
  1095  	_, err = txn1.InterDirc("insert t2 values (unhex('F0A48BAE'));")
  1096  	c.Assert(err, NotNil)
  1097  	txn1.Commit()
  1098  
  1099  	// Disable CheckMb4ValueInUTF8.
  1100  	form = make(url.Values)
  1101  	form.Set("check_mb4_value_in_utf8", "0")
  1102  	resp, err = ts.formStatus("/settings", form)
  1103  	c.Assert(err, IsNil)
  1104  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
  1105  	c.Assert(config.GetGlobalConfig().CheckMb4ValueInUTF8, Equals, false)
  1106  	dbt.mustInterDirc("insert t2 values (unhex('f09f8c80'));")
  1107  }
  1108  
  1109  func (ts *HTTPHandlerTestSuite) TestPprof(c *C) {
  1110  	ts.startServer(c)
  1111  	defer ts.stopServer(c)
  1112  	retryTime := 100
  1113  	for retry := 0; retry < retryTime; retry++ {
  1114  		resp, err := ts.fetchStatus("/debug/pprof/heap")
  1115  		if err == nil {
  1116  			ioutil.ReadAll(resp.Body)
  1117  			resp.Body.Close()
  1118  			return
  1119  		}
  1120  		time.Sleep(time.Millisecond * 10)
  1121  	}
  1122  	zaplog.Fatal("failed to get profile for %d retries in every 10 ms", zap.Int("retryTime", retryTime))
  1123  }
  1124  
  1125  func (ts *HTTPHandlerTestSuite) TestServerInfo(c *C) {
  1126  	ts.startServer(c)
  1127  	defer ts.stopServer(c)
  1128  	resp, err := ts.fetchStatus("/info")
  1129  	c.Assert(err, IsNil)
  1130  	defer resp.Body.Close()
  1131  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
  1132  	causetDecoder := json.NewCausetDecoder(resp.Body)
  1133  
  1134  	info := serverInfo{}
  1135  	err = causetDecoder.Decode(&info)
  1136  	c.Assert(err, IsNil)
  1137  
  1138  	cfg := config.GetGlobalConfig()
  1139  	c.Assert(info.IsTenant, IsTrue)
  1140  	c.Assert(info.IP, Equals, cfg.AdvertiseAddress)
  1141  	c.Assert(info.StatusPort, Equals, cfg.Status.StatusPort)
  1142  	c.Assert(info.Lease, Equals, cfg.Lease)
  1143  	c.Assert(info.Version, Equals, allegrosql.ServerVersion)
  1144  	c.Assert(info.GitHash, Equals, versioninfo.MilevaDBGitHash)
  1145  
  1146  	causetstore := ts.server.newEinsteinDBHandlerTool().CausetStore.(ekv.CausetStorage)
  1147  	do, err := stochastik.GetPetri(causetstore.(ekv.CausetStorage))
  1148  	c.Assert(err, IsNil)
  1149  	dbs := do.DBS()
  1150  	c.Assert(info.ID, Equals, dbs.GetID())
  1151  }
  1152  
  1153  func (ts *HTTPHandlerTestSerialSuite) TestAllServerInfo(c *C) {
  1154  	ts.startServer(c)
  1155  	defer ts.stopServer(c)
  1156  	resp, err := ts.fetchStatus("/info/all")
  1157  	c.Assert(err, IsNil)
  1158  	defer resp.Body.Close()
  1159  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
  1160  	causetDecoder := json.NewCausetDecoder(resp.Body)
  1161  
  1162  	clusterInfo := clusterServerInfo{}
  1163  	err = causetDecoder.Decode(&clusterInfo)
  1164  	c.Assert(err, IsNil)
  1165  
  1166  	c.Assert(clusterInfo.IsAllServerVersionConsistent, IsTrue)
  1167  	c.Assert(clusterInfo.ServersNum, Equals, 1)
  1168  
  1169  	causetstore := ts.server.newEinsteinDBHandlerTool().CausetStore.(ekv.CausetStorage)
  1170  	do, err := stochastik.GetPetri(causetstore.(ekv.CausetStorage))
  1171  	c.Assert(err, IsNil)
  1172  	dbs := do.DBS()
  1173  	c.Assert(clusterInfo.TenantID, Equals, dbs.GetID())
  1174  	serverInfo, ok := clusterInfo.AllServersInfo[dbs.GetID()]
  1175  	c.Assert(ok, Equals, true)
  1176  
  1177  	cfg := config.GetGlobalConfig()
  1178  	c.Assert(serverInfo.IP, Equals, cfg.AdvertiseAddress)
  1179  	c.Assert(serverInfo.StatusPort, Equals, cfg.Status.StatusPort)
  1180  	c.Assert(serverInfo.Lease, Equals, cfg.Lease)
  1181  	c.Assert(serverInfo.Version, Equals, allegrosql.ServerVersion)
  1182  	c.Assert(serverInfo.GitHash, Equals, versioninfo.MilevaDBGitHash)
  1183  	c.Assert(serverInfo.ID, Equals, dbs.GetID())
  1184  }
  1185  
  1186  func (ts *HTTPHandlerTestSuite) TestHotRegionInfo(c *C) {
  1187  	ts.startServer(c)
  1188  	defer ts.stopServer(c)
  1189  	resp, err := ts.fetchStatus("/regions/hot")
  1190  	c.Assert(err, IsNil)
  1191  	defer resp.Body.Close()
  1192  	c.Assert(resp.StatusCode, Equals, http.StatusBadRequest)
  1193  }
  1194  
  1195  func (ts *HTTPHandlerTestSuite) TestDebugZip(c *C) {
  1196  	ts.startServer(c)
  1197  	defer ts.stopServer(c)
  1198  	resp, err := ts.fetchStatus("/debug/zip?seconds=1")
  1199  	c.Assert(err, IsNil)
  1200  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
  1201  	b, err := httputil.DumpResponse(resp, true)
  1202  	c.Assert(err, IsNil)
  1203  	c.Assert(len(b), Greater, 0)
  1204  	c.Assert(resp.Body.Close(), IsNil)
  1205  }
  1206  
  1207  func (ts *HTTPHandlerTestSuite) TestCheckCN(c *C) {
  1208  	s := &Server{cfg: &config.Config{Security: config.Security{ClusterVerifyCN: []string{"a ", "b", "c"}}}}
  1209  	tlsConfig := &tls.Config{}
  1210  	s.setCNChecker(tlsConfig)
  1211  	c.Assert(tlsConfig.VerifyPeerCertificate, NotNil)
  1212  	err := tlsConfig.VerifyPeerCertificate(nil, [][]*x509.Certificate{{{Subject: pkix.Name{CommonName: "a"}}}})
  1213  	c.Assert(err, IsNil)
  1214  	err = tlsConfig.VerifyPeerCertificate(nil, [][]*x509.Certificate{{{Subject: pkix.Name{CommonName: "b"}}}})
  1215  	c.Assert(err, IsNil)
  1216  	err = tlsConfig.VerifyPeerCertificate(nil, [][]*x509.Certificate{{{Subject: pkix.Name{CommonName: "d"}}}})
  1217  	c.Assert(err, NotNil)
  1218  }
  1219  
  1220  func (ts *HTTPHandlerTestSuite) TestZipInfoForALLEGROSQL(c *C) {
  1221  	ts.startServer(c)
  1222  	defer ts.stopServer(c)
  1223  
  1224  	EDB, err := allegrosql.Open("allegrosql", ts.getDSN())
  1225  	c.Assert(err, IsNil, Commentf("Error connecting"))
  1226  	defer EDB.Close()
  1227  	dbt := &DBTest{c, EDB}
  1228  
  1229  	dbt.mustInterDirc("use test")
  1230  	dbt.mustInterDirc("create causet if not exists t (a int)")
  1231  
  1232  	urlValues := url.Values{
  1233  		"allegrosql": {"select * from t"},
  1234  		"current_db": {"test"},
  1235  	}
  1236  	resp, err := ts.formStatus("/debug/sub-optimal-plan", urlValues)
  1237  	c.Assert(err, IsNil)
  1238  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
  1239  	b, err := httputil.DumpResponse(resp, true)
  1240  	c.Assert(err, IsNil)
  1241  	c.Assert(len(b), Greater, 0)
  1242  	c.Assert(resp.Body.Close(), IsNil)
  1243  
  1244  	resp, err = ts.formStatus("/debug/sub-optimal-plan?pprof_time=5&timeout=0", urlValues)
  1245  	c.Assert(err, IsNil)
  1246  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
  1247  	b, err = httputil.DumpResponse(resp, true)
  1248  	c.Assert(err, IsNil)
  1249  	c.Assert(len(b), Greater, 0)
  1250  	c.Assert(resp.Body.Close(), IsNil)
  1251  
  1252  	resp, err = ts.formStatus("/debug/sub-optimal-plan?pprof_time=5", urlValues)
  1253  	c.Assert(err, IsNil)
  1254  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
  1255  	b, err = httputil.DumpResponse(resp, true)
  1256  	c.Assert(err, IsNil)
  1257  	c.Assert(len(b), Greater, 0)
  1258  	c.Assert(resp.Body.Close(), IsNil)
  1259  
  1260  	resp, err = ts.formStatus("/debug/sub-optimal-plan?timeout=1", urlValues)
  1261  	c.Assert(err, IsNil)
  1262  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
  1263  	b, err = httputil.DumpResponse(resp, true)
  1264  	c.Assert(err, IsNil)
  1265  	c.Assert(len(b), Greater, 0)
  1266  	c.Assert(resp.Body.Close(), IsNil)
  1267  
  1268  	urlValues.Set("current_db", "non_exists_db")
  1269  	resp, err = ts.formStatus("/debug/sub-optimal-plan", urlValues)
  1270  	c.Assert(err, IsNil)
  1271  	c.Assert(resp.StatusCode, Equals, http.StatusInternalServerError)
  1272  	b, err = ioutil.ReadAll(resp.Body)
  1273  	c.Assert(err, IsNil)
  1274  	c.Assert(string(b), Equals, "use database non_exists_db failed, err: [schemaReplicant:1049]Unknown database 'non_exists_db'\n")
  1275  	c.Assert(resp.Body.Close(), IsNil)
  1276  }
  1277  
  1278  func (ts *HTTPHandlerTestSuite) TestFailpointHandler(c *C) {
  1279  	defer ts.stopServer(c)
  1280  
  1281  	// start server without enabling failpoint integration
  1282  	ts.startServer(c)
  1283  	resp, err := ts.fetchStatus("/fail/")
  1284  	c.Assert(err, IsNil)
  1285  	c.Assert(resp.StatusCode, Equals, http.StatusNotFound)
  1286  	ts.stopServer(c)
  1287  
  1288  	// enable failpoint integration and start server
  1289  	c.Assert(failpoint.Enable("github.com/whtcorpsinc/milevadb/server/enableTestAPI", "return"), IsNil)
  1290  	ts.startServer(c)
  1291  	resp, err = ts.fetchStatus("/fail/")
  1292  	c.Assert(err, IsNil)
  1293  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
  1294  	b, err := ioutil.ReadAll(resp.Body)
  1295  	c.Assert(err, IsNil)
  1296  	c.Assert(strings.Contains(string(b), "github.com/whtcorpsinc/milevadb/server/enableTestAPI=return"), IsTrue)
  1297  	c.Assert(resp.Body.Close(), IsNil)
  1298  }
  1299  
  1300  func (ts *HTTPHandlerTestSuite) TestTestHandler(c *C) {
  1301  	defer ts.stopServer(c)
  1302  
  1303  	// start server without enabling failpoint integration
  1304  	ts.startServer(c)
  1305  	resp, err := ts.fetchStatus("/test")
  1306  	c.Assert(err, IsNil)
  1307  	c.Assert(resp.StatusCode, Equals, http.StatusNotFound)
  1308  	ts.stopServer(c)
  1309  
  1310  	// enable failpoint integration and start server
  1311  	c.Assert(failpoint.Enable("github.com/whtcorpsinc/milevadb/server/enableTestAPI", "return"), IsNil)
  1312  	ts.startServer(c)
  1313  
  1314  	resp, err = ts.fetchStatus("/test/gc/gc")
  1315  	c.Assert(err, IsNil)
  1316  	resp.Body.Close()
  1317  	c.Assert(resp.StatusCode, Equals, http.StatusBadRequest)
  1318  
  1319  	resp, err = ts.fetchStatus("/test/gc/resolvelock")
  1320  	c.Assert(err, IsNil)
  1321  	resp.Body.Close()
  1322  	c.Assert(resp.StatusCode, Equals, http.StatusBadRequest)
  1323  
  1324  	resp, err = ts.fetchStatus("/test/gc/resolvelock?safepoint=a")
  1325  	c.Assert(err, IsNil)
  1326  	resp.Body.Close()
  1327  	c.Assert(resp.StatusCode, Equals, http.StatusBadRequest)
  1328  
  1329  	resp, err = ts.fetchStatus("/test/gc/resolvelock?physical=1")
  1330  	c.Assert(err, IsNil)
  1331  	resp.Body.Close()
  1332  	c.Assert(resp.StatusCode, Equals, http.StatusBadRequest)
  1333  
  1334  	resp, err = ts.fetchStatus("/test/gc/resolvelock?physical=true")
  1335  	c.Assert(err, IsNil)
  1336  	resp.Body.Close()
  1337  	c.Assert(resp.StatusCode, Equals, http.StatusBadRequest)
  1338  
  1339  	resp, err = ts.fetchStatus("/test/gc/resolvelock?safepoint=10000&physical=true")
  1340  	c.Assert(err, IsNil)
  1341  	resp.Body.Close()
  1342  	c.Assert(resp.StatusCode, Equals, http.StatusOK)
  1343  }