From a696b43bc9461ee4fbf13663a0a27eb5d4b7af14 Mon Sep 17 00:00:00 2001 From: tison Date: Thu, 4 Nov 2021 18:33:02 +0800 Subject: [PATCH] server: migrate test-infra to testify for http_handler_test.go (#29374) --- server/http_handler_serial_test.go | 582 +++++++++++ server/http_handler_test.go | 1443 +++++++++------------------- server/main_test.go | 21 + server/server_test.go | 21 - testkit/dbtestkit.go | 5 + 5 files changed, 1076 insertions(+), 996 deletions(-) create mode 100644 server/http_handler_serial_test.go diff --git a/server/http_handler_serial_test.go b/server/http_handler_serial_test.go new file mode 100644 index 0000000000000..2cbd9bb7c3fb3 --- /dev/null +++ b/server/http_handler_serial_test.go @@ -0,0 +1,582 @@ +// Copyright 2021 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package server + +import ( + "bytes" + "database/sql" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "os" + "sort" + "strings" + "sync/atomic" + "testing" + "time" + + "github.com/pingcap/failpoint" + "github.com/pingcap/log" + "github.com/pingcap/tidb/config" + "github.com/pingcap/tidb/ddl" + "github.com/pingcap/tidb/kv" + "github.com/pingcap/tidb/parser/model" + "github.com/pingcap/tidb/parser/mysql" + "github.com/pingcap/tidb/session" + "github.com/pingcap/tidb/sessionctx/variable" + "github.com/pingcap/tidb/testkit" + "github.com/pingcap/tidb/util/deadlockhistory" + "github.com/pingcap/tidb/util/versioninfo" + "github.com/stretchr/testify/require" + "go.uber.org/zap" +) + +func TestPostSettings(t *testing.T) { + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + ts.prepareData(t) + defer ts.stopServer(t) + se, err := session.CreateSession(ts.store) + require.NoError(t, err) + + form := make(url.Values) + form.Set("log_level", "error") + form.Set("tidb_general_log", "1") + form.Set("tidb_enable_async_commit", "1") + form.Set("tidb_enable_1pc", "1") + resp, err := ts.formStatus("/settings", form) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + require.NoError(t, resp.Body.Close()) + require.Equal(t, zap.ErrorLevel, log.GetLevel()) + require.Equal(t, "error", config.GetGlobalConfig().Log.Level) + require.True(t, variable.ProcessGeneralLog.Load()) + val, err := variable.GetGlobalSystemVar(se.GetSessionVars(), variable.TiDBEnableAsyncCommit) + require.NoError(t, err) + require.Equal(t, variable.On, val) + val, err = variable.GetGlobalSystemVar(se.GetSessionVars(), variable.TiDBEnable1PC) + require.NoError(t, err) + require.Equal(t, variable.On, val) + + form = make(url.Values) + form.Set("log_level", "fatal") + form.Set("tidb_general_log", "0") + form.Set("tidb_enable_async_commit", "0") + form.Set("tidb_enable_1pc", "0") + resp, err = ts.formStatus("/settings", form) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + require.NoError(t, resp.Body.Close()) + require.False(t, variable.ProcessGeneralLog.Load()) + require.Equal(t, zap.FatalLevel, log.GetLevel()) + require.Equal(t, "fatal", config.GetGlobalConfig().Log.Level) + val, err = variable.GetGlobalSystemVar(se.GetSessionVars(), variable.TiDBEnableAsyncCommit) + require.NoError(t, err) + require.Equal(t, variable.Off, val) + val, err = variable.GetGlobalSystemVar(se.GetSessionVars(), variable.TiDBEnable1PC) + require.NoError(t, err) + require.Equal(t, variable.Off, val) + form.Set("log_level", os.Getenv("log_level")) + + // test ddl_slow_threshold + form = make(url.Values) + form.Set("ddl_slow_threshold", "200") + resp, err = ts.formStatus("/settings", form) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + require.NoError(t, resp.Body.Close()) + require.Equal(t, uint32(200), atomic.LoadUint32(&variable.DDLSlowOprThreshold)) + + // test check_mb4_value_in_utf8 + db, err := sql.Open("mysql", ts.getDSN()) + require.NoError(t, err) + defer func() { + err := db.Close() + require.NoError(t, err) + }() + dbt := testkit.NewDBTestKit(t, db) + + dbt.MustExec("create database tidb_test;") + dbt.MustExec("use tidb_test;") + dbt.MustExec("drop table if exists t2;") + dbt.MustExec("create table t2(a varchar(100) charset utf8);") + form.Set("check_mb4_value_in_utf8", "1") + resp, err = ts.formStatus("/settings", form) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + require.NoError(t, resp.Body.Close()) + require.Equal(t, true, config.GetGlobalConfig().CheckMb4ValueInUTF8) + txn1, err := dbt.GetDB().Begin() + require.NoError(t, err) + _, err = txn1.Exec("insert t2 values (unhex('F0A48BAE'));") + require.Error(t, err) + err = txn1.Commit() + require.NoError(t, err) + + // Disable CheckMb4ValueInUTF8. + form = make(url.Values) + form.Set("check_mb4_value_in_utf8", "0") + resp, err = ts.formStatus("/settings", form) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + require.NoError(t, resp.Body.Close()) + require.Equal(t, false, config.GetGlobalConfig().CheckMb4ValueInUTF8) + dbt.MustExec("insert t2 values (unhex('f09f8c80'));") + + // test deadlock_history_capacity + deadlockhistory.GlobalDeadlockHistory.Resize(10) + for i := 0; i < 10; i++ { + deadlockhistory.GlobalDeadlockHistory.Push(dummyRecord()) + } + form = make(url.Values) + form.Set("deadlock_history_capacity", "5") + resp, err = ts.formStatus("/settings", form) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, 5, len(deadlockhistory.GlobalDeadlockHistory.GetAll())) + require.Equal(t, uint64(6), deadlockhistory.GlobalDeadlockHistory.GetAll()[0].ID) + require.Equal(t, uint64(10), deadlockhistory.GlobalDeadlockHistory.GetAll()[4].ID) + deadlockhistory.GlobalDeadlockHistory.Push(dummyRecord()) + require.Equal(t, 5, len(deadlockhistory.GlobalDeadlockHistory.GetAll())) + require.Equal(t, uint64(7), deadlockhistory.GlobalDeadlockHistory.GetAll()[0].ID) + require.Equal(t, uint64(11), deadlockhistory.GlobalDeadlockHistory.GetAll()[4].ID) + form = make(url.Values) + form.Set("deadlock_history_capacity", "6") + resp, err = ts.formStatus("/settings", form) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + deadlockhistory.GlobalDeadlockHistory.Push(dummyRecord()) + require.Equal(t, 6, len(deadlockhistory.GlobalDeadlockHistory.GetAll())) + require.Equal(t, uint64(7), deadlockhistory.GlobalDeadlockHistory.GetAll()[0].ID) + require.Equal(t, uint64(12), deadlockhistory.GlobalDeadlockHistory.GetAll()[5].ID) + + // test deadlock_history_collect_retryable + form = make(url.Values) + form.Set("deadlock_history_collect_retryable", "true") + resp, err = ts.formStatus("/settings", form) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.True(t, config.GetGlobalConfig().PessimisticTxn.DeadlockHistoryCollectRetryable) + form = make(url.Values) + form.Set("deadlock_history_collect_retryable", "false") + resp, err = ts.formStatus("/settings", form) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.False(t, config.GetGlobalConfig().PessimisticTxn.DeadlockHistoryCollectRetryable) + form = make(url.Values) + form.Set("deadlock_history_collect_retryable", "123") + resp, err = ts.formStatus("/settings", form) + require.NoError(t, err) + require.Equal(t, 400, resp.StatusCode) + require.NoError(t, resp.Body.Close()) + + // restore original value. + config.GetGlobalConfig().CheckMb4ValueInUTF8 = true +} + +func TestAllServerInfo(t *testing.T) { + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + defer ts.stopServer(t) + resp, err := ts.fetchStatus("/info/all") + require.NoError(t, err) + defer func() { require.NoError(t, resp.Body.Close()) }() + require.Equal(t, http.StatusOK, resp.StatusCode) + decoder := json.NewDecoder(resp.Body) + + clusterInfo := clusterServerInfo{} + err = decoder.Decode(&clusterInfo) + require.NoError(t, err) + + require.True(t, clusterInfo.IsAllServerVersionConsistent) + require.Equal(t, 1, clusterInfo.ServersNum) + + store := ts.server.newTikvHandlerTool().Store.(kv.Storage) + do, err := session.GetDomain(store) + require.NoError(t, err) + ddl := do.DDL() + require.Equal(t, ddl.GetID(), clusterInfo.OwnerID) + serverInfo, ok := clusterInfo.AllServersInfo[ddl.GetID()] + require.Equal(t, true, ok) + + cfg := config.GetGlobalConfig() + require.Equal(t, cfg.AdvertiseAddress, serverInfo.IP) + require.Equal(t, cfg.Status.StatusPort, serverInfo.StatusPort) + require.Equal(t, cfg.Lease, serverInfo.Lease) + require.Equal(t, mysql.ServerVersion, serverInfo.Version) + require.Equal(t, versioninfo.TiDBGitHash, serverInfo.GitHash) + require.Equal(t, ddl.GetID(), serverInfo.ID) +} + +func TestRegionsFromMeta(t *testing.T) { + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + defer ts.stopServer(t) + resp, err := ts.fetchStatus("/regions/meta") + require.NoError(t, err) + defer func() { require.NoError(t, resp.Body.Close()) }() + require.Equal(t, http.StatusOK, resp.StatusCode) + + // Verify the resp body. + decoder := json.NewDecoder(resp.Body) + metas := make([]RegionMeta, 0) + err = decoder.Decode(&metas) + require.NoError(t, err) + for _, m := range metas { + require.True(t, m.ID != 0) + } + + // test no panic + require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/server/errGetRegionByIDEmpty", `return(true)`)) + defer func() { require.NoError(t, failpoint.Disable("github.com/pingcap/tidb/server/errGetRegionByIDEmpty")) }() + resp1, err := ts.fetchStatus("/regions/meta") + require.NoError(t, err) + defer func() { require.NoError(t, resp1.Body.Close()) }() +} + +func TestTiFlashReplica(t *testing.T) { + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + ts.prepareData(t) + defer ts.stopServer(t) + + db, err := sql.Open("mysql", ts.getDSN()) + require.NoError(t, err) + defer func() { + err := db.Close() + require.NoError(t, err) + }() + dbt := testkit.NewDBTestKit(t, db) + + defer func(originGC bool) { + if originGC { + ddl.EmulatorGCEnable() + } else { + ddl.EmulatorGCDisable() + } + }(ddl.IsEmulatorGCEnable()) + + // Disable emulator GC. + // Otherwise emulator GC will delete table record as soon as possible after execute drop table DDL. + ddl.EmulatorGCDisable() + gcTimeFormat := "20060102-15:04:05 -0700 MST" + timeBeforeDrop := time.Now().Add(0 - 48*60*60*time.Second).Format(gcTimeFormat) + safePointSQL := `INSERT HIGH_PRIORITY INTO mysql.tidb VALUES ('tikv_gc_safe_point', '%[1]s', ''),('tikv_gc_enable','true','') + ON DUPLICATE KEY + UPDATE variable_value = '%[1]s'` + // Set GC safe point and enable GC. + dbt.MustExec(fmt.Sprintf(safePointSQL, timeBeforeDrop)) + + resp, err := ts.fetchStatus("/tiflash/replica") + require.NoError(t, err) + decoder := json.NewDecoder(resp.Body) + var data []tableFlashReplicaInfo + err = decoder.Decode(&data) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, 0, len(data)) + + require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/infoschema/mockTiFlashStoreCount", `return(true)`)) + defer func() { + require.NoError(t, failpoint.Disable("github.com/pingcap/tidb/infoschema/mockTiFlashStoreCount")) + }() + + dbt.MustExec("use tidb") + dbt.MustExec("alter table test set tiflash replica 2 location labels 'a','b';") + + resp, err = ts.fetchStatus("/tiflash/replica") + require.NoError(t, err) + decoder = json.NewDecoder(resp.Body) + err = decoder.Decode(&data) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, 1, len(data)) + require.Equal(t, uint64(2), data[0].ReplicaCount) + require.Equal(t, "a,b", strings.Join(data[0].LocationLabels, ",")) + require.Equal(t, false, data[0].Available) + + resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(`{"id":84,"region_count":3,"flash_region_count":3}`))) + require.NoError(t, err) + require.NotNil(t, resp) + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, "[schema:1146]Table which ID = 84 does not exist.", string(body)) + + tbl, err := ts.domain.InfoSchema().TableByName(model.NewCIStr("tidb"), model.NewCIStr("test")) + require.NoError(t, err) + req := fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, tbl.Meta().ID) + resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req))) + require.NoError(t, err) + require.NotNil(t, resp) + body, err = io.ReadAll(resp.Body) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, "", string(body)) + + resp, err = ts.fetchStatus("/tiflash/replica") + require.NoError(t, err) + decoder = json.NewDecoder(resp.Body) + err = decoder.Decode(&data) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, 1, len(data)) + require.Equal(t, uint64(2), data[0].ReplicaCount) + require.Equal(t, "a,b", strings.Join(data[0].LocationLabels, ",")) + require.Equal(t, true, data[0].Available) + + // Should not take effect. + dbt.MustExec("alter table test set tiflash replica 2 location labels 'a','b';") + checkFunc := func() { + resp, err := ts.fetchStatus("/tiflash/replica") + require.NoError(t, err) + decoder = json.NewDecoder(resp.Body) + err = decoder.Decode(&data) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, 1, len(data)) + require.Equal(t, uint64(2), data[0].ReplicaCount) + require.Equal(t, "a,b", strings.Join(data[0].LocationLabels, ",")) + require.Equal(t, true, data[0].Available) + } + + // Test for get dropped table tiflash replica info. + dbt.MustExec("drop table test") + checkFunc() + + // Test unique table id replica info. + dbt.MustExec("flashback table test") + checkFunc() + dbt.MustExec("drop table test") + checkFunc() + dbt.MustExec("flashback table test") + checkFunc() + + // Test for partition table. + dbt.MustExec("alter table pt set tiflash replica 2 location labels 'a','b';") + dbt.MustExec("alter table test set tiflash replica 0;") + resp, err = ts.fetchStatus("/tiflash/replica") + require.NoError(t, err) + decoder = json.NewDecoder(resp.Body) + err = decoder.Decode(&data) + require.NoError(t, err) + err = resp.Body.Close() + require.NoError(t, err) + require.Equal(t, 3, len(data)) + require.Equal(t, uint64(2), data[0].ReplicaCount) + require.Equal(t, "a,b", strings.Join(data[0].LocationLabels, ",")) + require.Equal(t, false, data[0].Available) + + pid0 := data[0].ID + pid1 := data[1].ID + pid2 := data[2].ID + + // Mock for partition 1 replica was available. + req = fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, pid1) + resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req))) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + resp, err = ts.fetchStatus("/tiflash/replica") + require.NoError(t, err) + decoder = json.NewDecoder(resp.Body) + err = decoder.Decode(&data) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, 3, len(data)) + require.Equal(t, false, data[0].Available) + require.Equal(t, true, data[1].Available) + require.Equal(t, false, data[2].Available) + + // Mock for partition 0,2 replica was available. + req = fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, pid0) + resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req))) + require.NoError(t, err) + err = resp.Body.Close() + require.NoError(t, err) + req = fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, pid2) + resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req))) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + checkFunc = func() { + resp, err := ts.fetchStatus("/tiflash/replica") + require.NoError(t, err) + decoder = json.NewDecoder(resp.Body) + err = decoder.Decode(&data) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, 3, len(data)) + require.Equal(t, true, data[0].Available) + require.Equal(t, true, data[1].Available) + require.Equal(t, true, data[2].Available) + } + + // Test for get truncated table tiflash replica info. + dbt.MustExec("truncate table pt") + dbt.MustExec("alter table pt set tiflash replica 0;") + checkFunc() +} + +func TestFailpointHandler(t *testing.T) { + ts := createBasicHTTPHandlerTestSuite() + + // start server without enabling failpoint integration + ts.startServer(t) + defer ts.stopServer(t) + resp, err := ts.fetchStatus("/fail/") + require.NoError(t, err) + require.Equal(t, http.StatusNotFound, resp.StatusCode) + require.NoError(t, resp.Body.Close()) + ts.stopServer(t) + + // enable failpoint integration and start server + require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/server/enableTestAPI", "return")) + defer func() { require.NoError(t, failpoint.Disable("github.com/pingcap/tidb/server/enableTestAPI")) }() + ts.startServer(t) + resp, err = ts.fetchStatus("/fail/") + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + b, err := io.ReadAll(resp.Body) + require.NoError(t, err) + require.True(t, strings.Contains(string(b), "github.com/pingcap/tidb/server/enableTestAPI=return")) + require.NoError(t, resp.Body.Close()) +} + +func TestTestHandler(t *testing.T) { + ts := createBasicHTTPHandlerTestSuite() + + // start server without enabling failpoint integration + ts.startServer(t) + defer ts.stopServer(t) + resp, err := ts.fetchStatus("/test") + require.NoError(t, err) + require.Equal(t, http.StatusNotFound, resp.StatusCode) + require.NoError(t, resp.Body.Close()) + ts.stopServer(t) + + // enable failpoint integration and start server + require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/server/enableTestAPI", "return")) + defer func() { require.NoError(t, failpoint.Disable("github.com/pingcap/tidb/server/enableTestAPI")) }() + ts.startServer(t) + + resp, err = ts.fetchStatus("/test/gc/gc") + require.NoError(t, err) + err = resp.Body.Close() + require.NoError(t, err) + require.Equal(t, http.StatusBadRequest, resp.StatusCode) + + resp, err = ts.fetchStatus("/test/gc/resolvelock") + require.NoError(t, err) + err = resp.Body.Close() + require.NoError(t, err) + require.Equal(t, http.StatusBadRequest, resp.StatusCode) + + resp, err = ts.fetchStatus("/test/gc/resolvelock?safepoint=a") + require.NoError(t, err) + err = resp.Body.Close() + require.NoError(t, err) + require.Equal(t, http.StatusBadRequest, resp.StatusCode) + + resp, err = ts.fetchStatus("/test/gc/resolvelock?physical=1") + require.NoError(t, err) + err = resp.Body.Close() + require.NoError(t, err) + require.Equal(t, http.StatusBadRequest, resp.StatusCode) + + resp, err = ts.fetchStatus("/test/gc/resolvelock?physical=true") + require.NoError(t, err) + err = resp.Body.Close() + require.NoError(t, err) + require.Equal(t, http.StatusBadRequest, resp.StatusCode) + + resp, err = ts.fetchStatus("/test/gc/resolvelock?safepoint=10000&physical=true") + require.NoError(t, err) + err = resp.Body.Close() + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) +} + +func TestServerInfo(t *testing.T) { + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + defer ts.stopServer(t) + resp, err := ts.fetchStatus("/info") + require.NoError(t, err) + defer func() { require.NoError(t, resp.Body.Close()) }() + require.Equal(t, http.StatusOK, resp.StatusCode) + decoder := json.NewDecoder(resp.Body) + + info := serverInfo{} + err = decoder.Decode(&info) + require.NoError(t, err) + + cfg := config.GetGlobalConfig() + require.True(t, info.IsOwner) + require.Equal(t, cfg.AdvertiseAddress, info.IP) + require.Equal(t, cfg.Status.StatusPort, info.StatusPort) + require.Equal(t, cfg.Lease, info.Lease) + require.Equal(t, mysql.ServerVersion, info.Version) + require.Equal(t, versioninfo.TiDBGitHash, info.GitHash) + + store := ts.server.newTikvHandlerTool().Store.(kv.Storage) + do, err := session.GetDomain(store) + require.NoError(t, err) + d := do.DDL() + require.Equal(t, d.GetID(), info.ID) +} + +func TestGetSchemaStorage(t *testing.T) { + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + ts.prepareData(t) + defer ts.stopServer(t) + + do := ts.domain + h := do.StatsHandle() + do.SetStatsUpdating(true) + + tk := testkit.NewTestKit(t, ts.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (c int, d int, e char(5), index idx(e))") + tk.MustExec(`insert into t(c, d, e) values(1, 2, "c"), (2, 3, "d"), (3, 4, "e")`) + h.FlushStats() + + resp, err := ts.fetchStatus("/schema_storage/test") + require.NoError(t, err) + decoder := json.NewDecoder(resp.Body) + var tables []*schemaTableStorage + err = decoder.Decode(&tables) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Len(t, tables, 1) + expects := []string{`t`} + names := make([]string, len(tables)) + for i, v := range tables { + names[i] = v.TableName + } + + sort.Strings(names) + require.Equal(t, expects, names) + require.Equal(t, []int64{3, 18, 54, 0, 6, 0}, []int64{ + tables[0].TableRows, + tables[0].AvgRowLength, + tables[0].DataLength, + tables[0].MaxDataLength, + tables[0].IndexLength, + tables[0].DataFree, + }) +} diff --git a/server/http_handler_test.go b/server/http_handler_test.go index d78642b1651a0..3278732a0059f 100644 --- a/server/http_handler_test.go +++ b/server/http_handler_test.go @@ -27,19 +27,13 @@ import ( "net" "net/http" "net/http/httputil" - "net/url" - "os" "sort" - "strings" - "sync/atomic" + "testing" "time" - . "github.com/pingcap/check" - "github.com/pingcap/failpoint" "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/pingcap/log" "github.com/pingcap/tidb/config" - "github.com/pingcap/tidb/ddl" "github.com/pingcap/tidb/domain" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/meta" @@ -49,16 +43,15 @@ import ( "github.com/pingcap/tidb/sessionctx" "github.com/pingcap/tidb/sessionctx/binloginfo" "github.com/pingcap/tidb/sessionctx/stmtctx" - "github.com/pingcap/tidb/sessionctx/variable" "github.com/pingcap/tidb/store/helper" "github.com/pingcap/tidb/store/mockstore" "github.com/pingcap/tidb/tablecodec" + "github.com/pingcap/tidb/testkit" "github.com/pingcap/tidb/types" "github.com/pingcap/tidb/util/codec" "github.com/pingcap/tidb/util/deadlockhistory" "github.com/pingcap/tidb/util/rowcodec" - "github.com/pingcap/tidb/util/testkit" - "github.com/pingcap/tidb/util/versioninfo" + "github.com/stretchr/testify/require" "github.com/tikv/client-go/v2/tikv" "go.uber.org/zap" ) @@ -72,23 +65,14 @@ type basicHTTPHandlerTestSuite struct { sh *StatsHandler } -type HTTPHandlerTestSuite struct { - *basicHTTPHandlerTestSuite -} - -type HTTPHandlerTestSerialSuite struct { - *basicHTTPHandlerTestSuite -} - -var _ = Suite(&HTTPHandlerTestSuite{&basicHTTPHandlerTestSuite{}}) - -var _ = SerialSuites(&HTTPHandlerTestSerialSuite{&basicHTTPHandlerTestSuite{}}) - -func (ts *basicHTTPHandlerTestSuite) SetUpSuite(c *C) { +func createBasicHTTPHandlerTestSuite() *basicHTTPHandlerTestSuite { + ts := &basicHTTPHandlerTestSuite{} ts.testServerClient = newTestServerClient() + return ts } -func (ts *HTTPHandlerTestSuite) TestRegionIndexRange(c *C) { +func TestRegionIndexRange(t *testing.T) { + t.Parallel() sTableID := int64(3) sIndex := int64(11) eTableID := int64(9) @@ -107,7 +91,7 @@ func (ts *HTTPHandlerTestSuite) TestRegionIndexRange(c *C) { expectIndexValues = append(expectIndexValues, str) } encodedValue, err := codec.EncodeKey(&stmtctx.StatementContext{TimeZone: time.Local}, nil, indexValues...) - c.Assert(err, IsNil) + require.NoError(t, err) startKey := tablecodec.EncodeIndexSeekKey(sTableID, sIndex, encodedValue) recordPrefix := tablecodec.GenTableRecordPrefix(eTableID) @@ -119,13 +103,13 @@ func (ts *HTTPHandlerTestSuite) TestRegionIndexRange(c *C) { EndKey: endKey, } r, err := helper.NewRegionFrameRange(region) - c.Assert(err, IsNil) - c.Assert(r.First.IndexID, Equals, sIndex) - c.Assert(r.First.IsRecord, IsFalse) - c.Assert(r.First.RecordID, Equals, int64(0)) - c.Assert(r.First.IndexValues, DeepEquals, expectIndexValues) - c.Assert(r.Last.RecordID, Equals, recordID) - c.Assert(r.Last.IndexValues, IsNil) + require.NoError(t, err) + require.Equal(t, sIndex, r.First.IndexID) + require.False(t, r.First.IsRecord) + require.Equal(t, int64(0), r.First.RecordID) + require.Equal(t, expectIndexValues, r.First.IndexValues) + require.Equal(t, recordID, r.Last.RecordID) + require.Nil(t, r.Last.IndexValues) testCases := []struct { tableID int64 @@ -143,22 +127,23 @@ func (ts *HTTPHandlerTestSuite) TestRegionIndexRange(c *C) { {9, 10, true}, {10, 1, false}, } - for _, t := range testCases { + for _, c := range testCases { var f *helper.FrameItem - if t.indexID == 0 { - f = r.GetRecordFrame(t.tableID, "", "", false) + if c.indexID == 0 { + f = r.GetRecordFrame(c.tableID, "", "", false) } else { - f = r.GetIndexFrame(t.tableID, t.indexID, "", "", "") + f = r.GetIndexFrame(c.tableID, c.indexID, "", "", "") } - if t.isCover { - c.Assert(f, NotNil) + if c.isCover { + require.NotNil(t, f) } else { - c.Assert(f, IsNil) + require.Nil(t, f) } } } -func (ts *HTTPHandlerTestSuite) TestRegionCommonHandleRange(c *C) { +func TestRegionCommonHandleRange(t *testing.T) { + t.Parallel() sTableID := int64(3) indexValues := []types.Datum{ types.NewIntDatum(100), @@ -174,7 +159,7 @@ func (ts *HTTPHandlerTestSuite) TestRegionCommonHandleRange(c *C) { expectIndexValues = append(expectIndexValues, str) } encodedValue, err := codec.EncodeKey(&stmtctx.StatementContext{TimeZone: time.Local}, nil, indexValues...) - c.Assert(err, IsNil) + require.NoError(t, err) startKey := tablecodec.EncodeRowKey(sTableID, encodedValue) @@ -184,16 +169,17 @@ func (ts *HTTPHandlerTestSuite) TestRegionCommonHandleRange(c *C) { EndKey: nil, } r, err := helper.NewRegionFrameRange(region) - c.Assert(err, IsNil) - c.Assert(r.First.IsRecord, IsTrue) - c.Assert(r.First.RecordID, Equals, int64(0)) - c.Assert(r.First.IndexValues, DeepEquals, expectIndexValues) - c.Assert(r.First.IndexName, Equals, "PRIMARY") - c.Assert(r.Last.RecordID, Equals, int64(0)) - c.Assert(r.Last.IndexValues, IsNil) + require.NoError(t, err) + require.True(t, r.First.IsRecord) + require.Equal(t, int64(0), r.First.RecordID) + require.Equal(t, expectIndexValues, r.First.IndexValues) + require.Equal(t, "PRIMARY", r.First.IndexName) + require.Equal(t, int64(0), r.Last.RecordID) + require.Nil(t, r.Last.IndexValues) } -func (ts *HTTPHandlerTestSuite) TestRegionIndexRangeWithEndNoLimit(c *C) { +func TestRegionIndexRangeWithEndNoLimit(t *testing.T) { + t.Parallel() sTableID := int64(15) startKey := tablecodec.GenTableRecordPrefix(sTableID) endKey := []byte("z_aaaaafdfd") @@ -203,14 +189,15 @@ func (ts *HTTPHandlerTestSuite) TestRegionIndexRangeWithEndNoLimit(c *C) { EndKey: endKey, } r, err := helper.NewRegionFrameRange(region) - c.Assert(err, IsNil) - c.Assert(r.First.IsRecord, IsTrue) - c.Assert(r.Last.IsRecord, IsTrue) - c.Assert(r.GetRecordFrame(300, "", "", false), NotNil) - c.Assert(r.GetIndexFrame(200, 100, "", "", ""), NotNil) + require.NoError(t, err) + require.True(t, r.First.IsRecord) + require.True(t, r.Last.IsRecord) + require.NotNil(t, r.GetRecordFrame(300, "", "", false)) + require.NotNil(t, r.GetIndexFrame(200, 100, "", "", "")) } -func (ts *HTTPHandlerTestSuite) TestRegionIndexRangeWithStartNoLimit(c *C) { +func TestRegionIndexRangeWithStartNoLimit(t *testing.T) { + t.Parallel() eTableID := int64(9) startKey := []byte("m_aaaaafdfd") endKey := tablecodec.GenTableRecordPrefix(eTableID) @@ -220,56 +207,60 @@ func (ts *HTTPHandlerTestSuite) TestRegionIndexRangeWithStartNoLimit(c *C) { EndKey: endKey, } r, err := helper.NewRegionFrameRange(region) - c.Assert(err, IsNil) - c.Assert(r.First.IsRecord, IsFalse) - c.Assert(r.Last.IsRecord, IsTrue) - c.Assert(r.GetRecordFrame(3, "", "", false), NotNil) - c.Assert(r.GetIndexFrame(8, 1, "", "", ""), NotNil) + require.NoError(t, err) + require.False(t, r.First.IsRecord) + require.True(t, r.Last.IsRecord) + require.NotNil(t, r.GetRecordFrame(3, "", "", false)) + require.NotNil(t, r.GetIndexFrame(8, 1, "", "", "")) } -func (ts *HTTPHandlerTestSuite) TestRegionsAPI(c *C) { - ts.startServer(c) - defer ts.stopServer(c) - ts.prepareData(c) +func TestRegionsAPI(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + defer ts.stopServer(t) + ts.prepareData(t) resp, err := ts.fetchStatus("/tables/tidb/t/regions") - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusOK) - defer resp.Body.Close() + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + defer func() { require.NoError(t, resp.Body.Close()) }() decoder := json.NewDecoder(resp.Body) var data TableRegions err = decoder.Decode(&data) - c.Assert(err, IsNil) - c.Assert(len(data.RecordRegions) > 0, IsTrue) + require.NoError(t, err) + require.True(t, len(data.RecordRegions) > 0) // list region for _, region := range data.RecordRegions { - c.Assert(ts.regionContainsTable(c, region.ID, data.TableID), IsTrue) + require.True(t, ts.regionContainsTable(t, region.ID, data.TableID)) } } -func (ts *HTTPHandlerTestSuite) TestRegionsAPIForClusterIndex(c *C) { - ts.startServer(c) - defer ts.stopServer(c) - ts.prepareData(c) +func TestRegionsAPIForClusterIndex(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + defer ts.stopServer(t) + ts.prepareData(t) resp, err := ts.fetchStatus("/tables/tidb/t/regions") - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusOK) - defer resp.Body.Close() + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + defer func() { require.NoError(t, resp.Body.Close()) }() decoder := json.NewDecoder(resp.Body) var data TableRegions err = decoder.Decode(&data) - c.Assert(err, IsNil) - c.Assert(len(data.RecordRegions) > 0, IsTrue) + require.NoError(t, err) + require.True(t, len(data.RecordRegions) > 0) // list region for _, region := range data.RecordRegions { resp, err := ts.fetchStatus(fmt.Sprintf("/regions/%d", region.ID)) - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusOK) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) decoder := json.NewDecoder(resp.Body) var data RegionDetail err = decoder.Decode(&data) - c.Assert(err, IsNil) + require.NoError(t, err) frameCnt := 0 for _, f := range data.Frames { if f.DBName == "tidb" && f.TableName == "t" { @@ -277,41 +268,43 @@ func (ts *HTTPHandlerTestSuite) TestRegionsAPIForClusterIndex(c *C) { } } // frameCnt = clustered primary key + secondary index(idx) = 2. - c.Assert(frameCnt, Equals, 2) - c.Assert(resp.Body.Close(), IsNil) + require.Equal(t, 2, frameCnt) + require.NoError(t, resp.Body.Close()) } } -func (ts *HTTPHandlerTestSuite) TestRangesAPI(c *C) { - ts.startServer(c) - defer ts.stopServer(c) - ts.prepareData(c) +func TestRangesAPI(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + defer ts.stopServer(t) + ts.prepareData(t) resp, err := ts.fetchStatus("/tables/tidb/t/ranges") - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusOK) - defer resp.Body.Close() + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + defer func() { require.NoError(t, resp.Body.Close()) }() decoder := json.NewDecoder(resp.Body) var data TableRanges err = decoder.Decode(&data) - c.Assert(err, IsNil) - c.Assert(data.TableName, Equals, "t") - c.Assert(len(data.Indices), Equals, 2) + require.NoError(t, err) + require.Equal(t, "t", data.TableName) + require.Equal(t, 2, len(data.Indices)) _, ok := data.Indices["PRIMARY"] - c.Assert(ok, IsTrue) + require.True(t, ok) _, ok = data.Indices["idx"] - c.Assert(ok, IsTrue) + require.True(t, ok) } -func (ts *HTTPHandlerTestSuite) regionContainsTable(c *C, regionID uint64, tableID int64) bool { +func (ts *basicHTTPHandlerTestSuite) regionContainsTable(t *testing.T, regionID uint64, tableID int64) bool { resp, err := ts.fetchStatus(fmt.Sprintf("/regions/%d", regionID)) - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusOK) - defer resp.Body.Close() + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + defer func() { require.NoError(t, resp.Body.Close()) }() decoder := json.NewDecoder(resp.Body) var data RegionDetail err = decoder.Decode(&data) - c.Assert(err, IsNil) + require.NoError(t, err) for _, index := range data.Frames { if index.TableID == tableID { return true @@ -320,162 +313,145 @@ func (ts *HTTPHandlerTestSuite) regionContainsTable(c *C, regionID uint64, table return false } -func (ts *HTTPHandlerTestSuite) TestListTableRegions(c *C) { - ts.startServer(c) - defer ts.stopServer(c) - ts.prepareData(c) +func TestListTableRegions(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + defer ts.stopServer(t) + ts.prepareData(t) // Test list table regions with error resp, err := ts.fetchStatus("/tables/fdsfds/aaa/regions") - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.Equal(t, http.StatusBadRequest, resp.StatusCode) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/tables/tidb/pt/regions") - c.Assert(err, IsNil) + require.NoError(t, err) var data []*TableRegions dec := json.NewDecoder(resp.Body) err = dec.Decode(&data) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) region := data[1] resp, err = ts.fetchStatus(fmt.Sprintf("/regions/%d", region.TableID)) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) } -func (ts *HTTPHandlerTestSuite) TestListTableRanges(c *C) { - ts.startServer(c) - defer ts.stopServer(c) - ts.prepareData(c) +func TestListTableRanges(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + defer ts.stopServer(t) + ts.prepareData(t) // Test list table regions with error resp, err := ts.fetchStatus("/tables/fdsfds/aaa/ranges") - c.Assert(err, IsNil) - defer resp.Body.Close() - c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) + require.NoError(t, err) + defer func() { require.NoError(t, resp.Body.Close()) }() + require.Equal(t, http.StatusBadRequest, resp.StatusCode) resp, err = ts.fetchStatus("/tables/tidb/pt/ranges") - c.Assert(err, IsNil) - defer resp.Body.Close() + require.NoError(t, err) + defer func() { require.NoError(t, resp.Body.Close()) }() var data []*TableRanges dec := json.NewDecoder(resp.Body) err = dec.Decode(&data) - c.Assert(err, IsNil) - c.Assert(len(data), Equals, 3) + require.NoError(t, err) + require.Equal(t, 3, len(data)) for i, partition := range data { - c.Assert(partition.TableName, Equals, fmt.Sprintf("p%d", i)) + require.Equal(t, fmt.Sprintf("p%d", i), partition.TableName) } } -func (ts *HTTPHandlerTestSuite) TestGetRegionByIDWithError(c *C) { - ts.startServer(c) - defer ts.stopServer(c) +func TestGetRegionByIDWithError(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + defer ts.stopServer(t) resp, err := ts.fetchStatus("/regions/xxx") - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) - defer resp.Body.Close() + require.NoError(t, err) + require.Equal(t, http.StatusBadRequest, resp.StatusCode) + defer func() { require.NoError(t, resp.Body.Close()) }() } -func (ts *HTTPHandlerTestSuite) TestBinlogRecover(c *C) { - ts.startServer(c) - defer ts.stopServer(c) +func TestBinlogRecover(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + defer ts.stopServer(t) binloginfo.EnableSkipBinlogFlag() - c.Assert(binloginfo.IsBinlogSkipped(), Equals, true) + require.Equal(t, true, binloginfo.IsBinlogSkipped()) resp, err := ts.fetchStatus("/binlog/recover") - c.Assert(err, IsNil) - defer resp.Body.Close() - c.Assert(resp.StatusCode, Equals, http.StatusOK) - c.Assert(binloginfo.IsBinlogSkipped(), Equals, false) + require.NoError(t, err) + defer func() { require.NoError(t, resp.Body.Close()) }() + require.Equal(t, http.StatusOK, resp.StatusCode) + require.Equal(t, false, binloginfo.IsBinlogSkipped()) // Invalid operation will use the default operation. binloginfo.EnableSkipBinlogFlag() - c.Assert(binloginfo.IsBinlogSkipped(), Equals, true) + require.Equal(t, true, binloginfo.IsBinlogSkipped()) resp, err = ts.fetchStatus("/binlog/recover?op=abc") - c.Assert(err, IsNil) - defer resp.Body.Close() - c.Assert(resp.StatusCode, Equals, http.StatusOK) - c.Assert(binloginfo.IsBinlogSkipped(), Equals, false) + require.NoError(t, err) + defer func() { require.NoError(t, resp.Body.Close()) }() + require.Equal(t, http.StatusOK, resp.StatusCode) + require.Equal(t, false, binloginfo.IsBinlogSkipped()) binloginfo.EnableSkipBinlogFlag() - c.Assert(binloginfo.IsBinlogSkipped(), Equals, true) + require.Equal(t, true, binloginfo.IsBinlogSkipped()) resp, err = ts.fetchStatus("/binlog/recover?op=abc&seconds=1") - c.Assert(err, IsNil) - defer resp.Body.Close() - c.Assert(resp.StatusCode, Equals, http.StatusOK) - c.Assert(binloginfo.IsBinlogSkipped(), Equals, false) + require.NoError(t, err) + defer func() { require.NoError(t, resp.Body.Close()) }() + require.Equal(t, http.StatusOK, resp.StatusCode) + require.Equal(t, false, binloginfo.IsBinlogSkipped()) binloginfo.EnableSkipBinlogFlag() - c.Assert(binloginfo.IsBinlogSkipped(), Equals, true) + require.Equal(t, true, binloginfo.IsBinlogSkipped()) binloginfo.AddOneSkippedCommitter() resp, err = ts.fetchStatus("/binlog/recover?op=abc&seconds=1") - c.Assert(err, IsNil) - defer resp.Body.Close() - c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) - c.Assert(binloginfo.IsBinlogSkipped(), Equals, false) + require.NoError(t, err) + defer func() { require.NoError(t, resp.Body.Close()) }() + require.Equal(t, http.StatusBadRequest, resp.StatusCode) + require.Equal(t, false, binloginfo.IsBinlogSkipped()) binloginfo.RemoveOneSkippedCommitter() binloginfo.AddOneSkippedCommitter() - c.Assert(binloginfo.SkippedCommitterCount(), Equals, int32(1)) + require.Equal(t, int32(1), binloginfo.SkippedCommitterCount()) resp, err = ts.fetchStatus("/binlog/recover?op=reset") - c.Assert(err, IsNil) - defer resp.Body.Close() - c.Assert(resp.StatusCode, Equals, http.StatusOK) - c.Assert(binloginfo.SkippedCommitterCount(), Equals, int32(0)) + require.NoError(t, err) + defer func() { require.NoError(t, resp.Body.Close()) }() + require.Equal(t, http.StatusOK, resp.StatusCode) + require.Equal(t, int32(0), binloginfo.SkippedCommitterCount()) binloginfo.EnableSkipBinlogFlag() resp, err = ts.fetchStatus("/binlog/recover?op=nowait") - c.Assert(err, IsNil) - defer resp.Body.Close() - c.Assert(resp.StatusCode, Equals, http.StatusOK) - c.Assert(binloginfo.IsBinlogSkipped(), Equals, false) + require.NoError(t, err) + defer func() { require.NoError(t, resp.Body.Close()) }() + require.Equal(t, http.StatusOK, resp.StatusCode) + require.Equal(t, false, binloginfo.IsBinlogSkipped()) // Only the first should work. binloginfo.EnableSkipBinlogFlag() resp, err = ts.fetchStatus("/binlog/recover?op=nowait&op=reset") - c.Assert(err, IsNil) - defer resp.Body.Close() - c.Assert(resp.StatusCode, Equals, http.StatusOK) - c.Assert(binloginfo.IsBinlogSkipped(), Equals, false) + require.NoError(t, err) + defer func() { require.NoError(t, resp.Body.Close()) }() + require.Equal(t, http.StatusOK, resp.StatusCode) + require.Equal(t, false, binloginfo.IsBinlogSkipped()) resp, err = ts.fetchStatus("/binlog/recover?op=status") - c.Assert(err, IsNil) - defer resp.Body.Close() - c.Assert(resp.StatusCode, Equals, http.StatusOK) + require.NoError(t, err) + defer func() { require.NoError(t, resp.Body.Close()) }() + require.Equal(t, http.StatusOK, resp.StatusCode) } -func (ts *HTTPHandlerTestSuite) TestRegionsFromMeta(c *C) { - ts.startServer(c) - defer ts.stopServer(c) - resp, err := ts.fetchStatus("/regions/meta") - c.Assert(err, IsNil) - defer resp.Body.Close() - c.Assert(resp.StatusCode, Equals, http.StatusOK) - - // Verify the resp body. - decoder := json.NewDecoder(resp.Body) - metas := make([]RegionMeta, 0) - err = decoder.Decode(&metas) - c.Assert(err, IsNil) - for _, meta := range metas { - c.Assert(meta.ID != 0, IsTrue) - } - - // test no panic - c.Assert(failpoint.Enable("github.com/pingcap/tidb/server/errGetRegionByIDEmpty", `return(true)`), IsNil) - resp1, err := ts.fetchStatus("/regions/meta") - c.Assert(err, IsNil) - defer resp1.Body.Close() - c.Assert(failpoint.Disable("github.com/pingcap/tidb/server/errGetRegionByIDEmpty"), IsNil) -} - -func (ts *basicHTTPHandlerTestSuite) startServer(c *C) { +func (ts *basicHTTPHandlerTestSuite) startServer(t *testing.T) { var err error ts.store, err = mockstore.NewMockStore() - c.Assert(err, IsNil) + require.NoError(t, err) ts.domain, err = session.BootstrapSession(ts.store) - c.Assert(err, IsNil) + require.NoError(t, err) ts.tidbdrv = NewTiDBDriver(ts.store) cfg := newTestConfig() @@ -483,20 +459,21 @@ func (ts *basicHTTPHandlerTestSuite) startServer(c *C) { cfg.Port = 0 cfg.Status.StatusPort = 0 cfg.Status.ReportStatus = true + cfg.Socket = fmt.Sprintf("/tmp/%s.sock", t.Name()) server, err := NewServer(cfg, ts.tidbdrv) - c.Assert(err, IsNil) + require.NoError(t, err) ts.port = getPortFromTCPAddr(server.listener.Addr()) ts.statusPort = getPortFromTCPAddr(server.statusListener.Addr()) ts.server = server go func() { err := server.Run() - c.Assert(err, IsNil) + require.NoError(t, err) }() ts.waitUntilServerOnline() do, err := session.GetDomain(ts.store) - c.Assert(err, IsNil) + require.NoError(t, err) ts.sh = &StatsHandler{do} } @@ -504,7 +481,7 @@ func getPortFromTCPAddr(addr net.Addr) uint { return uint(addr.(*net.TCPAddr).Port) } -func (ts *basicHTTPHandlerTestSuite) stopServer(c *C) { +func (ts *basicHTTPHandlerTestSuite) stopServer(t *testing.T) { if ts.server != nil { ts.server.Close() } @@ -512,90 +489,92 @@ func (ts *basicHTTPHandlerTestSuite) stopServer(c *C) { ts.domain.Close() } if ts.store != nil { - ts.store.Close() + require.NoError(t, ts.store.Close()) } } -func (ts *basicHTTPHandlerTestSuite) prepareData(c *C) { +func (ts *basicHTTPHandlerTestSuite) prepareData(t *testing.T) { db, err := sql.Open("mysql", ts.getDSN()) - c.Assert(err, IsNil, Commentf("Error connecting")) + require.NoError(t, err) defer func() { err := db.Close() - c.Assert(err, IsNil) + require.NoError(t, err) }() - dbt := &DBTest{c, db} - - dbt.mustExec("create database tidb;") - dbt.mustExec("use tidb;") - dbt.mustExec("create table tidb.test (a int auto_increment primary key, b varchar(20));") - dbt.mustExec("insert tidb.test values (1, 1);") - txn1, err := dbt.db.Begin() - c.Assert(err, IsNil) + dbt := testkit.NewDBTestKit(t, db) + + dbt.MustExec("create database tidb;") + dbt.MustExec("use tidb;") + dbt.MustExec("create table tidb.test (a int auto_increment primary key, b varchar(20));") + dbt.MustExec("insert tidb.test values (1, 1);") + txn1, err := dbt.GetDB().Begin() + require.NoError(t, err) _, err = txn1.Exec("update tidb.test set b = b + 1 where a = 1;") - c.Assert(err, IsNil) + require.NoError(t, err) _, err = txn1.Exec("insert tidb.test values (2, 2);") - c.Assert(err, IsNil) + require.NoError(t, err) _, err = txn1.Exec("insert tidb.test (a) values (3);") - c.Assert(err, IsNil) + require.NoError(t, err) _, err = txn1.Exec("insert tidb.test values (4, '');") - c.Assert(err, IsNil) + require.NoError(t, err) err = txn1.Commit() - c.Assert(err, IsNil) - dbt.mustExec("alter table tidb.test add index idx1 (a, b);") - dbt.mustExec("alter table tidb.test add unique index idx2 (a, b);") + require.NoError(t, err) + dbt.MustExec("alter table tidb.test add index idx1 (a, b);") + dbt.MustExec("alter table tidb.test add unique index idx2 (a, b);") - dbt.mustExec(`create table tidb.pt (a int primary key, b varchar(20), key idx(a, b)) + dbt.MustExec(`create table tidb.pt (a int primary key, b varchar(20), key idx(a, b)) partition by range (a) (partition p0 values less than (256), partition p1 values less than (512), partition p2 values less than (1024))`) - txn2, err := dbt.db.Begin() - c.Assert(err, IsNil) + txn2, err := dbt.GetDB().Begin() + require.NoError(t, err) _, err = txn2.Exec("insert into tidb.pt values (42, '123')") - c.Assert(err, IsNil) + require.NoError(t, err) _, err = txn2.Exec("insert into tidb.pt values (256, 'b')") - c.Assert(err, IsNil) + require.NoError(t, err) _, err = txn2.Exec("insert into tidb.pt values (666, 'def')") - c.Assert(err, IsNil) + require.NoError(t, err) err = txn2.Commit() - c.Assert(err, IsNil) - dbt.mustExec("drop table if exists t") - dbt.mustExec("create table t (a double, b varchar(20), c int, primary key(a,b) clustered, key idx(c))") - dbt.mustExec("insert into t values(1.1,'111',1),(2.2,'222',2)") + require.NoError(t, err) + dbt.MustExec("drop table if exists t") + dbt.MustExec("create table t (a double, b varchar(20), c int, primary key(a,b) clustered, key idx(c))") + dbt.MustExec("insert into t values(1.1,'111',1),(2.2,'222',2)") } -func decodeKeyMvcc(closer io.ReadCloser, c *C, valid bool) { +func decodeKeyMvcc(closer io.ReadCloser, t *testing.T, valid bool) { decoder := json.NewDecoder(closer) var data helper.MvccKV err := decoder.Decode(&data) - c.Assert(err, IsNil) + require.NoError(t, err) if valid { - c.Assert(data.Value.Info, NotNil) - c.Assert(len(data.Value.Info.Writes), Greater, 0) + require.NotNil(t, data.Value.Info) + require.Greater(t, len(data.Value.Info.Writes), 0) } else { - c.Assert(data.Value.Info.Lock, IsNil) - c.Assert(data.Value.Info.Writes, IsNil) - c.Assert(data.Value.Info.Values, IsNil) + require.Nil(t, data.Value.Info.Lock) + require.Nil(t, data.Value.Info.Writes) + require.Nil(t, data.Value.Info.Values) } } -func (ts *HTTPHandlerTestSuite) TestGetTableMVCC(c *C) { - ts.startServer(c) - ts.prepareData(c) - defer ts.stopServer(c) +func TestGetTableMVCC(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + ts.prepareData(t) + defer ts.stopServer(t) resp, err := ts.fetchStatus("/mvcc/key/tidb/test/1") - c.Assert(err, IsNil) + require.NoError(t, err) decoder := json.NewDecoder(resp.Body) var data helper.MvccKV err = decoder.Decode(&data) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(data.Value, NotNil) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.NotNil(t, data.Value) info := data.Value.Info - c.Assert(info, NotNil) - c.Assert(len(info.Writes), Greater, 0) + require.NotNil(t, info) + require.Greater(t, len(info.Writes), 0) // TODO: Unistore will not return Op_Lock. // Use this workaround to support two backend, we can remove this hack after deprecated mocktikv. @@ -609,276 +588,98 @@ func (ts *HTTPHandlerTestSuite) TestGetTableMVCC(c *C) { } resp, err = ts.fetchStatus(fmt.Sprintf("/mvcc/txn/%d/tidb/test", startTs)) - c.Assert(err, IsNil) + require.NoError(t, err) var p2 helper.MvccKV decoder = json.NewDecoder(resp.Body) err = decoder.Decode(&p2) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) for i, expect := range info.Values { v2 := p2.Value.Info.Values[i].Value - c.Assert(v2, BytesEquals, expect.Value) + require.Equal(t, expect.Value, v2) } hexKey := p2.Key resp, err = ts.fetchStatus("/mvcc/hex/" + hexKey) - c.Assert(err, IsNil) + require.NoError(t, err) decoder = json.NewDecoder(resp.Body) var data2 helper.MvccKV err = decoder.Decode(&data2) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(data2, DeepEquals, data) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, data, data2) resp, err = ts.fetchStatus("/mvcc/key/tidb/test/1?decode=true") - c.Assert(err, IsNil) + require.NoError(t, err) decoder = json.NewDecoder(resp.Body) var data3 map[string]interface{} err = decoder.Decode(&data3) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(data3["key"], NotNil) - c.Assert(data3["info"], NotNil) - c.Assert(data3["data"], NotNil) - c.Assert(data3["decode_error"], IsNil) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.NotNil(t, data3["key"]) + require.NotNil(t, data3["info"]) + require.NotNil(t, data3["data"]) + require.Nil(t, data3["decode_error"]) resp, err = ts.fetchStatus("/mvcc/key/tidb/pt(p0)/42?decode=true") - c.Assert(err, IsNil) + require.NoError(t, err) decoder = json.NewDecoder(resp.Body) var data4 map[string]interface{} err = decoder.Decode(&data4) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(data4["key"], NotNil) - c.Assert(data4["info"], NotNil) - c.Assert(data4["data"], NotNil) - c.Assert(data4["decode_error"], IsNil) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.NotNil(t, data4["key"]) + require.NotNil(t, data4["info"]) + require.NotNil(t, data4["data"]) + require.Nil(t, data4["decode_error"]) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/mvcc/key/tidb/t/42") - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.Equal(t, http.StatusBadRequest, resp.StatusCode) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/mvcc/key/tidb/t?a=1.1") - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.Equal(t, http.StatusBadRequest, resp.StatusCode) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/mvcc/key/tidb/t?a=1.1&b=111&decode=1") - c.Assert(err, IsNil) + require.NoError(t, err) decoder = json.NewDecoder(resp.Body) var data5 map[string]interface{} err = decoder.Decode(&data5) - c.Assert(err, IsNil) - c.Assert(data4["key"], NotNil) - c.Assert(data4["info"], NotNil) - c.Assert(data4["data"], NotNil) - c.Assert(data4["decode_error"], IsNil) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.NotNil(t, data4["key"]) + require.NotNil(t, data4["info"]) + require.NotNil(t, data4["data"]) + require.Nil(t, data4["decode_error"]) + require.NoError(t, resp.Body.Close()) } -func (ts *HTTPHandlerTestSuite) TestGetMVCCNotFound(c *C) { - ts.startServer(c) - ts.prepareData(c) - defer ts.stopServer(c) +func TestGetMVCCNotFound(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + ts.prepareData(t) + defer ts.stopServer(t) resp, err := ts.fetchStatus("/mvcc/key/tidb/test/1234") - c.Assert(err, IsNil) + require.NoError(t, err) decoder := json.NewDecoder(resp.Body) var data helper.MvccKV err = decoder.Decode(&data) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(data.Value.Info.Lock, IsNil) - c.Assert(data.Value.Info.Writes, IsNil) - c.Assert(data.Value.Info.Values, IsNil) -} - -func (ts *HTTPHandlerTestSuite) TestTiFlashReplica(c *C) { - ts.startServer(c) - ts.prepareData(c) - defer ts.stopServer(c) - - db, err := sql.Open("mysql", ts.getDSN()) - c.Assert(err, IsNil, Commentf("Error connecting")) - defer func() { - err := db.Close() - c.Assert(err, IsNil) - }() - dbt := &DBTest{c, db} - - defer func(originGC bool) { - if originGC { - ddl.EmulatorGCEnable() - } else { - ddl.EmulatorGCDisable() - } - }(ddl.IsEmulatorGCEnable()) - - // Disable emulator GC. - // Otherwise emulator GC will delete table record as soon as possible after execute drop table DDL. - ddl.EmulatorGCDisable() - gcTimeFormat := "20060102-15:04:05 -0700 MST" - timeBeforeDrop := time.Now().Add(0 - 48*60*60*time.Second).Format(gcTimeFormat) - safePointSQL := `INSERT HIGH_PRIORITY INTO mysql.tidb VALUES ('tikv_gc_safe_point', '%[1]s', ''),('tikv_gc_enable','true','') - ON DUPLICATE KEY - UPDATE variable_value = '%[1]s'` - // Set GC safe point and enable GC. - dbt.mustExec(fmt.Sprintf(safePointSQL, timeBeforeDrop)) - - resp, err := ts.fetchStatus("/tiflash/replica") - c.Assert(err, IsNil) - decoder := json.NewDecoder(resp.Body) - var data []tableFlashReplicaInfo - err = decoder.Decode(&data) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(len(data), Equals, 0) - - c.Assert(failpoint.Enable("github.com/pingcap/tidb/infoschema/mockTiFlashStoreCount", `return(true)`), IsNil) - defer func() { - err = failpoint.Disable("github.com/pingcap/tidb/infoschema/mockTiFlashStoreCount") - c.Assert(err, IsNil) - }() - - dbt.mustExec("use tidb") - dbt.mustExec("alter table test set tiflash replica 2 location labels 'a','b';") - - resp, err = ts.fetchStatus("/tiflash/replica") - c.Assert(err, IsNil) - decoder = json.NewDecoder(resp.Body) - err = decoder.Decode(&data) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(len(data), Equals, 1) - c.Assert(data[0].ReplicaCount, Equals, uint64(2)) - c.Assert(strings.Join(data[0].LocationLabels, ","), Equals, "a,b") - c.Assert(data[0].Available, Equals, false) - - resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(`{"id":84,"region_count":3,"flash_region_count":3}`))) - c.Assert(err, IsNil) - c.Assert(resp, NotNil) - body, err := io.ReadAll(resp.Body) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(string(body), Equals, "[schema:1146]Table which ID = 84 does not exist.") - - t, err := ts.domain.InfoSchema().TableByName(model.NewCIStr("tidb"), model.NewCIStr("test")) - c.Assert(err, IsNil) - req := fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, t.Meta().ID) - resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req))) - c.Assert(err, IsNil) - c.Assert(resp, NotNil) - body, err = io.ReadAll(resp.Body) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(string(body), Equals, "") - - resp, err = ts.fetchStatus("/tiflash/replica") - c.Assert(err, IsNil) - decoder = json.NewDecoder(resp.Body) - err = decoder.Decode(&data) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(len(data), Equals, 1) - c.Assert(data[0].ReplicaCount, Equals, uint64(2)) - c.Assert(strings.Join(data[0].LocationLabels, ","), Equals, "a,b") - c.Assert(data[0].Available, Equals, true) // The status should be true now. - - // Should not take effect. - dbt.mustExec("alter table test set tiflash replica 2 location labels 'a','b';") - checkFunc := func() { - resp, err := ts.fetchStatus("/tiflash/replica") - c.Assert(err, IsNil) - decoder = json.NewDecoder(resp.Body) - err = decoder.Decode(&data) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(len(data), Equals, 1) - c.Assert(data[0].ReplicaCount, Equals, uint64(2)) - c.Assert(strings.Join(data[0].LocationLabels, ","), Equals, "a,b") - c.Assert(data[0].Available, Equals, true) // The status should be true now. - } - - // Test for get dropped table tiflash replica info. - dbt.mustExec("drop table test") - checkFunc() - - // Test unique table id replica info. - dbt.mustExec("flashback table test") - checkFunc() - dbt.mustExec("drop table test") - checkFunc() - dbt.mustExec("flashback table test") - checkFunc() - - // Test for partition table. - dbt.mustExec("alter table pt set tiflash replica 2 location labels 'a','b';") - dbt.mustExec("alter table test set tiflash replica 0;") - resp, err = ts.fetchStatus("/tiflash/replica") - c.Assert(err, IsNil) - decoder = json.NewDecoder(resp.Body) - err = decoder.Decode(&data) - c.Assert(err, IsNil) - err = resp.Body.Close() - c.Assert(err, IsNil) - c.Assert(len(data), Equals, 3) - c.Assert(data[0].ReplicaCount, Equals, uint64(2)) - c.Assert(strings.Join(data[0].LocationLabels, ","), Equals, "a,b") - c.Assert(data[0].Available, Equals, false) - - pid0 := data[0].ID - pid1 := data[1].ID - pid2 := data[2].ID - - // Mock for partition 1 replica was available. - req = fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, pid1) - resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req))) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - resp, err = ts.fetchStatus("/tiflash/replica") - c.Assert(err, IsNil) - decoder = json.NewDecoder(resp.Body) - err = decoder.Decode(&data) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(len(data), Equals, 3) - c.Assert(data[0].Available, Equals, false) - c.Assert(data[1].Available, Equals, true) - c.Assert(data[2].Available, Equals, false) - - // Mock for partition 0,2 replica was available. - req = fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, pid0) - resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req))) - c.Assert(err, IsNil) - err = resp.Body.Close() - c.Assert(err, IsNil) - req = fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, pid2) - resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req))) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - checkFunc = func() { - resp, err := ts.fetchStatus("/tiflash/replica") - c.Assert(err, IsNil) - decoder = json.NewDecoder(resp.Body) - err = decoder.Decode(&data) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(len(data), Equals, 3) - c.Assert(data[0].Available, Equals, true) - c.Assert(data[1].Available, Equals, true) - c.Assert(data[2].Available, Equals, true) - } - - // Test for get truncated table tiflash replica info. - dbt.mustExec("truncate table pt") - dbt.mustExec("alter table pt set tiflash replica 0;") - checkFunc() + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Nil(t, data.Value.Info.Lock) + require.Nil(t, data.Value.Info.Writes) + require.Nil(t, data.Value.Info.Values) } -func (ts *HTTPHandlerTestSuite) TestDecodeColumnValue(c *C) { - ts.startServer(c) - ts.prepareData(c) - defer ts.stopServer(c) +func TestDecodeColumnValue(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + ts.prepareData(t) + defer ts.stopServer(t) // column is a structure used for test type column struct { @@ -905,22 +706,22 @@ func (ts *HTTPHandlerTestSuite) TestDecodeColumnValue(c *C) { rd := rowcodec.Encoder{Enable: true} sc := &stmtctx.StatementContext{TimeZone: time.UTC} bs, err := tablecodec.EncodeRow(sc, row, colIDs, nil, nil, &rd) - c.Assert(err, IsNil) - c.Assert(bs, NotNil) + require.NoError(t, err) + require.NotNil(t, bs) bin := base64.StdEncoding.EncodeToString(bs) unitTest := func(col *column) { path := fmt.Sprintf("/tables/%d/%v/%d/%d?rowBin=%s", col.id, col.tp.Tp, col.tp.Flag, col.tp.Flen, bin) resp, err := ts.fetchStatus(path) - c.Assert(err, IsNil, Commentf("url:%s", ts.statusURL(path))) + require.NoErrorf(t, err, "url: %v", ts.statusURL(path)) decoder := json.NewDecoder(resp.Body) var data interface{} err = decoder.Decode(&data) - c.Assert(err, IsNil, Commentf("url:%v\ndata%v", ts.statusURL(path), data)) - c.Assert(resp.Body.Close(), IsNil) + require.NoErrorf(t, err, "url: %v\ndata: %v", ts.statusURL(path), data) + require.NoError(t, resp.Body.Close()) colVal, err := types.DatumsToString([]types.Datum{row[col.id-1]}, false) - c.Assert(err, IsNil) - c.Assert(data, Equals, colVal, Commentf("url:%v", ts.statusURL(path))) + require.NoError(t, err) + require.Equalf(t, colVal, data, "url: %v", ts.statusURL(path)) } for _, col := range cols { @@ -940,192 +741,198 @@ func (ts *HTTPHandlerTestSuite) TestDecodeColumnValue(c *C) { unitTest(cols[3]) } -func (ts *HTTPHandlerTestSuite) TestGetIndexMVCC(c *C) { - ts.startServer(c) - ts.prepareData(c) - defer ts.stopServer(c) +func TestGetIndexMVCC(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + ts.prepareData(t) + defer ts.stopServer(t) // tests for normal index key resp, err := ts.fetchStatus("/mvcc/index/tidb/test/idx1/1?a=1&b=2") - c.Assert(err, IsNil) - decodeKeyMvcc(resp.Body, c, true) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + decodeKeyMvcc(resp.Body, t, true) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/mvcc/index/tidb/test/idx2/1?a=1&b=2") - c.Assert(err, IsNil) - decodeKeyMvcc(resp.Body, c, true) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + decodeKeyMvcc(resp.Body, t, true) + require.NoError(t, resp.Body.Close()) // tests for index key which includes null resp, err = ts.fetchStatus("/mvcc/index/tidb/test/idx1/3?a=3&b") - c.Assert(err, IsNil) - decodeKeyMvcc(resp.Body, c, true) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + decodeKeyMvcc(resp.Body, t, true) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/mvcc/index/tidb/test/idx2/3?a=3&b") - c.Assert(err, IsNil) - decodeKeyMvcc(resp.Body, c, true) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + decodeKeyMvcc(resp.Body, t, true) + require.NoError(t, resp.Body.Close()) // tests for index key which includes empty string resp, err = ts.fetchStatus("/mvcc/index/tidb/test/idx1/4?a=4&b=") - c.Assert(err, IsNil) - decodeKeyMvcc(resp.Body, c, true) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + decodeKeyMvcc(resp.Body, t, true) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/mvcc/index/tidb/test/idx2/3?a=4&b=") - c.Assert(err, IsNil) - decodeKeyMvcc(resp.Body, c, true) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + decodeKeyMvcc(resp.Body, t, true) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/mvcc/index/tidb/t/idx?a=1.1&b=111&c=1") - c.Assert(err, IsNil) - decodeKeyMvcc(resp.Body, c, true) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + decodeKeyMvcc(resp.Body, t, true) + require.NoError(t, resp.Body.Close()) // tests for wrong key resp, err = ts.fetchStatus("/mvcc/index/tidb/test/idx1/5?a=5&b=1") - c.Assert(err, IsNil) - decodeKeyMvcc(resp.Body, c, false) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + decodeKeyMvcc(resp.Body, t, false) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/mvcc/index/tidb/test/idx2/5?a=5&b=1") - c.Assert(err, IsNil) - decodeKeyMvcc(resp.Body, c, false) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + decodeKeyMvcc(resp.Body, t, false) + require.NoError(t, resp.Body.Close()) // tests for missing column value resp, err = ts.fetchStatus("/mvcc/index/tidb/test/idx1/1?a=1") - c.Assert(err, IsNil) + require.NoError(t, err) decoder := json.NewDecoder(resp.Body) var data1 helper.MvccKV err = decoder.Decode(&data1) - c.Assert(err, NotNil) - c.Assert(resp.Body.Close(), IsNil) + require.Error(t, err) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/mvcc/index/tidb/test/idx2/1?a=1") - c.Assert(err, IsNil) + require.NoError(t, err) decoder = json.NewDecoder(resp.Body) var data2 helper.MvccKV err = decoder.Decode(&data2) - c.Assert(err, NotNil) - c.Assert(resp.Body.Close(), IsNil) + require.Error(t, err) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/mvcc/index/tidb/pt(p2)/idx/666?a=666&b=def") - c.Assert(err, IsNil) - decodeKeyMvcc(resp.Body, c, true) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + decodeKeyMvcc(resp.Body, t, true) + require.NoError(t, resp.Body.Close()) } -func (ts *HTTPHandlerTestSuite) TestGetSettings(c *C) { - ts.startServer(c) - ts.prepareData(c) - defer ts.stopServer(c) +func TestGetSettings(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + ts.prepareData(t) + defer ts.stopServer(t) resp, err := ts.fetchStatus("/settings") - c.Assert(err, IsNil) + require.NoError(t, err) decoder := json.NewDecoder(resp.Body) var settings *config.Config err = decoder.Decode(&settings) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) var configBytes []byte configBytes, err = json.Marshal(config.GetGlobalConfig()) - c.Assert(err, IsNil) + require.NoError(t, err) var settingBytes []byte settingBytes, err = json.Marshal(settings) - c.Assert(err, IsNil) - c.Assert(settingBytes, DeepEquals, configBytes) + require.NoError(t, err) + require.Equal(t, configBytes, settingBytes) } -func (ts *HTTPHandlerTestSuite) TestGetSchema(c *C) { - ts.startServer(c) - ts.prepareData(c) - defer ts.stopServer(c) +func TestGetSchema(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + ts.prepareData(t) + defer ts.stopServer(t) resp, err := ts.fetchStatus("/schema") - c.Assert(err, IsNil) + require.NoError(t, err) decoder := json.NewDecoder(resp.Body) var dbs []*model.DBInfo err = decoder.Decode(&dbs) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) expects := []string{"information_schema", "metrics_schema", "mysql", "performance_schema", "test", "tidb"} names := make([]string, len(dbs)) for i, v := range dbs { names[i] = v.Name.L } sort.Strings(names) - c.Assert(names, DeepEquals, expects) + require.Equal(t, expects, names) resp, err = ts.fetchStatus("/schema?table_id=5") - c.Assert(err, IsNil) - var t *model.TableInfo + require.NoError(t, err) + var ti *model.TableInfo decoder = json.NewDecoder(resp.Body) - err = decoder.Decode(&t) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(t.Name.L, Equals, "user") + err = decoder.Decode(&ti) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, "user", ti.Name.L) resp, err = ts.fetchStatus("/schema?table_id=a") - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/schema?table_id=1") - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/schema?table_id=-1") - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/schema/tidb") - c.Assert(err, IsNil) + require.NoError(t, err) var lt []*model.TableInfo decoder = json.NewDecoder(resp.Body) err = decoder.Decode(<) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(len(lt), Greater, 0) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Greater(t, len(lt), 0) resp, err = ts.fetchStatus("/schema/abc") - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/schema/tidb/test") - c.Assert(err, IsNil) + require.NoError(t, err) decoder = json.NewDecoder(resp.Body) - err = decoder.Decode(&t) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(t.Name.L, Equals, "test") + err = decoder.Decode(&ti) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, "test", ti.Name.L) resp, err = ts.fetchStatus("/schema/tidb/abc") - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/db-table/5") - c.Assert(err, IsNil) + require.NoError(t, err) var dbtbl *dbTableInfo decoder = json.NewDecoder(resp.Body) err = decoder.Decode(&dbtbl) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(dbtbl.TableInfo.Name.L, Equals, "user") - c.Assert(dbtbl.DBInfo.Name.L, Equals, "mysql") + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, "user", dbtbl.TableInfo.Name.L) + require.Equal(t, "mysql", dbtbl.DBInfo.Name.L) se, err := session.CreateSession(ts.store) - c.Assert(err, IsNil) - c.Assert(dbtbl.SchemaVersion, Equals, domain.GetDomain(se.(sessionctx.Context)).InfoSchema().SchemaMetaVersion()) + require.NoError(t, err) + require.Equal(t, domain.GetDomain(se.(sessionctx.Context)).InfoSchema().SchemaMetaVersion(), dbtbl.SchemaVersion) db, err := sql.Open("mysql", ts.getDSN()) - c.Assert(err, IsNil, Commentf("Error connecting")) + require.NoError(t, err) defer func() { err := db.Close() - c.Assert(err, IsNil) + require.NoError(t, err) }() - dbt := &DBTest{c, db} + dbt := testkit.NewDBTestKit(t, db) - dbt.mustExec("create database if not exists test;") - dbt.mustExec("use test;") - dbt.mustExec(` create table t1 (id int KEY) + dbt.MustExec("create database if not exists test;") + dbt.MustExec("use test;") + dbt.MustExec(` create table t1 (id int KEY) partition by range (id) ( PARTITION p0 VALUES LESS THAN (3), PARTITION p1 VALUES LESS THAN (5), @@ -1133,84 +940,39 @@ func (ts *HTTPHandlerTestSuite) TestGetSchema(c *C) { PARTITION p3 VALUES LESS THAN (9))`) resp, err = ts.fetchStatus("/schema/test/t1") - c.Assert(err, IsNil) + require.NoError(t, err) decoder = json.NewDecoder(resp.Body) - err = decoder.Decode(&t) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(t.Name.L, Equals, "t1") + err = decoder.Decode(&ti) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, "t1", ti.Name.L) - resp, err = ts.fetchStatus(fmt.Sprintf("/db-table/%v", t.GetPartitionInfo().Definitions[0].ID)) - c.Assert(err, IsNil) + resp, err = ts.fetchStatus(fmt.Sprintf("/db-table/%v", ti.GetPartitionInfo().Definitions[0].ID)) + require.NoError(t, err) decoder = json.NewDecoder(resp.Body) err = decoder.Decode(&dbtbl) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(dbtbl.TableInfo.Name.L, Equals, "t1") - c.Assert(dbtbl.DBInfo.Name.L, Equals, "test") - c.Assert(dbtbl.TableInfo, DeepEquals, t) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, "t1", dbtbl.TableInfo.Name.L) + require.Equal(t, "test", dbtbl.DBInfo.Name.L) + require.Equal(t, ti, dbtbl.TableInfo) } -func (ts *HTTPHandlerTestSuite) TestGetSchemaStorage(c *C) { - ts.startServer(c) - ts.prepareData(c) - defer ts.stopServer(c) - - do := ts.domain - h := do.StatsHandle() - do.SetStatsUpdating(true) - - tk := testkit.NewTestKitWithInit(c, ts.store) - tk.MustExec("use test") - tk.MustExec("drop table if exists t") - tk.MustExec("create table t (c int, d int, e char(5), index idx(e))") - tk.MustExec(`insert into t(c, d, e) values(1, 2, "c"), (2, 3, "d"), (3, 4, "e")`) - h.FlushStats() - - resp, err := ts.fetchStatus("/schema_storage/test") - c.Assert(err, IsNil) - decoder := json.NewDecoder(resp.Body) - var tables []*schemaTableStorage - err = decoder.Decode(&tables) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(len(tables), Equals, 1) - expects := []string{`t`} - names := make([]string, len(tables)) - for i, v := range tables { - names[i] = v.TableName - } - - sort.Strings(names) - c.Assert(names, DeepEquals, expects) - - c.Assert( - []int64{ - tables[0].TableRows, - tables[0].AvgRowLength, - tables[0].DataLength, - tables[0].MaxDataLength, - tables[0].IndexLength, - tables[0].DataFree, - }, - DeepEquals, - []int64{3, 18, 54, 0, 6, 0}, - ) -} - -func (ts *HTTPHandlerTestSuite) TestAllHistory(c *C) { - ts.startServer(c) - ts.prepareData(c) - defer ts.stopServer(c) +func TestAllHistory(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + ts.prepareData(t) + defer ts.stopServer(t) resp, err := ts.fetchStatus("/ddl/history/?limit=3") - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/ddl/history/?limit=-1") - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) resp, err = ts.fetchStatus("/ddl/history") - c.Assert(err, IsNil) + require.NoError(t, err) decoder := json.NewDecoder(resp.Body) var jobs []*model.Job @@ -1220,172 +982,32 @@ func (ts *HTTPHandlerTestSuite) TestAllHistory(c *C) { txn, _ := store.Begin() txnMeta := meta.NewMeta(txn) _, err = txnMeta.GetAllHistoryDDLJobs() - c.Assert(err, IsNil) + require.NoError(t, err) data, _ := txnMeta.GetAllHistoryDDLJobs() err = decoder.Decode(&jobs) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(jobs, DeepEquals, data) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, data, jobs) } func dummyRecord() *deadlockhistory.DeadlockRecord { return &deadlockhistory.DeadlockRecord{} } -func (ts *HTTPHandlerTestSerialSuite) TestPostSettings(c *C) { - ts.startServer(c) - ts.prepareData(c) - defer ts.stopServer(c) - se, err := session.CreateSession(ts.store) - c.Assert(err, IsNil) - - form := make(url.Values) - form.Set("log_level", "error") - form.Set("tidb_general_log", "1") - form.Set("tidb_enable_async_commit", "1") - form.Set("tidb_enable_1pc", "1") - resp, err := ts.formStatus("/settings", form) - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusOK) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(log.GetLevel(), Equals, zap.ErrorLevel) - c.Assert(config.GetGlobalConfig().Log.Level, Equals, "error") - c.Assert(variable.ProcessGeneralLog.Load(), IsTrue) - val, err := variable.GetGlobalSystemVar(se.GetSessionVars(), variable.TiDBEnableAsyncCommit) - c.Assert(err, IsNil) - c.Assert(val, Equals, variable.On) - val, err = variable.GetGlobalSystemVar(se.GetSessionVars(), variable.TiDBEnable1PC) - c.Assert(err, IsNil) - c.Assert(val, Equals, variable.On) - - form = make(url.Values) - form.Set("log_level", "fatal") - form.Set("tidb_general_log", "0") - form.Set("tidb_enable_async_commit", "0") - form.Set("tidb_enable_1pc", "0") - resp, err = ts.formStatus("/settings", form) - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusOK) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(variable.ProcessGeneralLog.Load(), IsFalse) - c.Assert(log.GetLevel(), Equals, zap.FatalLevel) - c.Assert(config.GetGlobalConfig().Log.Level, Equals, "fatal") - val, err = variable.GetGlobalSystemVar(se.GetSessionVars(), variable.TiDBEnableAsyncCommit) - c.Assert(err, IsNil) - c.Assert(val, Equals, variable.Off) - val, err = variable.GetGlobalSystemVar(se.GetSessionVars(), variable.TiDBEnable1PC) - c.Assert(err, IsNil) - c.Assert(val, Equals, variable.Off) - form.Set("log_level", os.Getenv("log_level")) - - // test ddl_slow_threshold - form = make(url.Values) - form.Set("ddl_slow_threshold", "200") - resp, err = ts.formStatus("/settings", form) - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusOK) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(atomic.LoadUint32(&variable.DDLSlowOprThreshold), Equals, uint32(200)) - - // test check_mb4_value_in_utf8 - db, err := sql.Open("mysql", ts.getDSN()) - c.Assert(err, IsNil, Commentf("Error connecting")) - defer func() { - err := db.Close() - c.Assert(err, IsNil) - }() - dbt := &DBTest{c, db} - - dbt.mustExec("create database tidb_test;") - dbt.mustExec("use tidb_test;") - dbt.mustExec("drop table if exists t2;") - dbt.mustExec("create table t2(a varchar(100) charset utf8);") - form.Set("check_mb4_value_in_utf8", "1") - resp, err = ts.formStatus("/settings", form) - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusOK) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(config.GetGlobalConfig().CheckMb4ValueInUTF8, Equals, true) - txn1, err := dbt.db.Begin() - c.Assert(err, IsNil) - _, err = txn1.Exec("insert t2 values (unhex('F0A48BAE'));") - c.Assert(err, NotNil) - err = txn1.Commit() - c.Assert(err, IsNil) - - // Disable CheckMb4ValueInUTF8. - form = make(url.Values) - form.Set("check_mb4_value_in_utf8", "0") - resp, err = ts.formStatus("/settings", form) - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusOK) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(config.GetGlobalConfig().CheckMb4ValueInUTF8, Equals, false) - dbt.mustExec("insert t2 values (unhex('f09f8c80'));") - - // test deadlock_history_capacity - deadlockhistory.GlobalDeadlockHistory.Resize(10) - for i := 0; i < 10; i++ { - deadlockhistory.GlobalDeadlockHistory.Push(dummyRecord()) - } - form = make(url.Values) - form.Set("deadlock_history_capacity", "5") - resp, err = ts.formStatus("/settings", form) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(len(deadlockhistory.GlobalDeadlockHistory.GetAll()), Equals, 5) - c.Assert(deadlockhistory.GlobalDeadlockHistory.GetAll()[0].ID, Equals, uint64(6)) - c.Assert(deadlockhistory.GlobalDeadlockHistory.GetAll()[4].ID, Equals, uint64(10)) - deadlockhistory.GlobalDeadlockHistory.Push(dummyRecord()) - c.Assert(len(deadlockhistory.GlobalDeadlockHistory.GetAll()), Equals, 5) - c.Assert(deadlockhistory.GlobalDeadlockHistory.GetAll()[0].ID, Equals, uint64(7)) - c.Assert(deadlockhistory.GlobalDeadlockHistory.GetAll()[4].ID, Equals, uint64(11)) - form = make(url.Values) - form.Set("deadlock_history_capacity", "6") - resp, err = ts.formStatus("/settings", form) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - deadlockhistory.GlobalDeadlockHistory.Push(dummyRecord()) - c.Assert(len(deadlockhistory.GlobalDeadlockHistory.GetAll()), Equals, 6) - c.Assert(deadlockhistory.GlobalDeadlockHistory.GetAll()[0].ID, Equals, uint64(7)) - c.Assert(deadlockhistory.GlobalDeadlockHistory.GetAll()[5].ID, Equals, uint64(12)) - - // test deadlock_history_collect_retryable - form = make(url.Values) - form.Set("deadlock_history_collect_retryable", "true") - resp, err = ts.formStatus("/settings", form) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(config.GetGlobalConfig().PessimisticTxn.DeadlockHistoryCollectRetryable, IsTrue) - form = make(url.Values) - form.Set("deadlock_history_collect_retryable", "false") - resp, err = ts.formStatus("/settings", form) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(config.GetGlobalConfig().PessimisticTxn.DeadlockHistoryCollectRetryable, IsFalse) - form = make(url.Values) - form.Set("deadlock_history_collect_retryable", "123") - resp, err = ts.formStatus("/settings", form) - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, 400) - c.Assert(resp.Body.Close(), IsNil) - - // restore original value. - config.GetGlobalConfig().CheckMb4ValueInUTF8 = true -} - -func (ts *HTTPHandlerTestSuite) TestPprof(c *C) { - ts.startServer(c) - defer ts.stopServer(c) +func TestPprof(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + defer ts.stopServer(t) retryTime := 100 for retry := 0; retry < retryTime; retry++ { resp, err := ts.fetchStatus("/debug/pprof/heap") if err == nil { _, err = io.ReadAll(resp.Body) - c.Assert(err, IsNil) + require.NoError(t, err) err = resp.Body.Close() - c.Assert(err, IsNil) + require.NoError(t, err) return } time.Sleep(time.Millisecond * 10) @@ -1393,200 +1015,71 @@ func (ts *HTTPHandlerTestSuite) TestPprof(c *C) { log.Fatal("failed to get profile for %d retries in every 10 ms", zap.Int("retryTime", retryTime)) } -func (ts *HTTPHandlerTestSuite) TestServerInfo(c *C) { - ts.startServer(c) - defer ts.stopServer(c) - resp, err := ts.fetchStatus("/info") - c.Assert(err, IsNil) - defer resp.Body.Close() - c.Assert(resp.StatusCode, Equals, http.StatusOK) - decoder := json.NewDecoder(resp.Body) - - info := serverInfo{} - err = decoder.Decode(&info) - c.Assert(err, IsNil) - - cfg := config.GetGlobalConfig() - c.Assert(info.IsOwner, IsTrue) - c.Assert(info.IP, Equals, cfg.AdvertiseAddress) - c.Assert(info.StatusPort, Equals, cfg.Status.StatusPort) - c.Assert(info.Lease, Equals, cfg.Lease) - c.Assert(info.Version, Equals, mysql.ServerVersion) - c.Assert(info.GitHash, Equals, versioninfo.TiDBGitHash) - - store := ts.server.newTikvHandlerTool().Store.(kv.Storage) - do, err := session.GetDomain(store) - c.Assert(err, IsNil) - ddl := do.DDL() - c.Assert(info.ID, Equals, ddl.GetID()) -} - -func (ts *HTTPHandlerTestSerialSuite) TestAllServerInfo(c *C) { - ts.startServer(c) - defer ts.stopServer(c) - resp, err := ts.fetchStatus("/info/all") - c.Assert(err, IsNil) - defer resp.Body.Close() - c.Assert(resp.StatusCode, Equals, http.StatusOK) - decoder := json.NewDecoder(resp.Body) - - clusterInfo := clusterServerInfo{} - err = decoder.Decode(&clusterInfo) - c.Assert(err, IsNil) - - c.Assert(clusterInfo.IsAllServerVersionConsistent, IsTrue) - c.Assert(clusterInfo.ServersNum, Equals, 1) - - store := ts.server.newTikvHandlerTool().Store.(kv.Storage) - do, err := session.GetDomain(store) - c.Assert(err, IsNil) - ddl := do.DDL() - c.Assert(clusterInfo.OwnerID, Equals, ddl.GetID()) - serverInfo, ok := clusterInfo.AllServersInfo[ddl.GetID()] - c.Assert(ok, Equals, true) - - cfg := config.GetGlobalConfig() - c.Assert(serverInfo.IP, Equals, cfg.AdvertiseAddress) - c.Assert(serverInfo.StatusPort, Equals, cfg.Status.StatusPort) - c.Assert(serverInfo.Lease, Equals, cfg.Lease) - c.Assert(serverInfo.Version, Equals, mysql.ServerVersion) - c.Assert(serverInfo.GitHash, Equals, versioninfo.TiDBGitHash) - c.Assert(serverInfo.ID, Equals, ddl.GetID()) -} - -func (ts *HTTPHandlerTestSuite) TestHotRegionInfo(c *C) { - ts.startServer(c) - defer ts.stopServer(c) +func TestHotRegionInfo(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + defer ts.stopServer(t) resp, err := ts.fetchStatus("/regions/hot") - c.Assert(err, IsNil) - defer resp.Body.Close() - c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) + require.NoError(t, err) + defer func() { require.NoError(t, resp.Body.Close()) }() + require.Equal(t, http.StatusBadRequest, resp.StatusCode) } -func (ts *HTTPHandlerTestSuite) TestDebugZip(c *C) { - ts.startServer(c) - defer ts.stopServer(c) +func TestDebugZip(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() + ts.startServer(t) + defer ts.stopServer(t) resp, err := ts.fetchStatus("/debug/zip?seconds=1") - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusOK) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) b, err := httputil.DumpResponse(resp, true) - c.Assert(err, IsNil) - c.Assert(len(b), Greater, 0) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.Greater(t, len(b), 0) + require.NoError(t, resp.Body.Close()) } -func (ts *HTTPHandlerTestSuite) TestCheckCN(c *C) { +func TestCheckCN(t *testing.T) { + t.Parallel() s := &Server{cfg: &config.Config{Security: config.Security{ClusterVerifyCN: []string{"a ", "b", "c"}}}} tlsConfig := &tls.Config{} s.setCNChecker(tlsConfig) - c.Assert(tlsConfig.VerifyPeerCertificate, NotNil) + require.NotNil(t, tlsConfig.VerifyPeerCertificate) err := tlsConfig.VerifyPeerCertificate(nil, [][]*x509.Certificate{{{Subject: pkix.Name{CommonName: "a"}}}}) - c.Assert(err, IsNil) + require.NoError(t, err) err = tlsConfig.VerifyPeerCertificate(nil, [][]*x509.Certificate{{{Subject: pkix.Name{CommonName: "b"}}}}) - c.Assert(err, IsNil) + require.NoError(t, err) err = tlsConfig.VerifyPeerCertificate(nil, [][]*x509.Certificate{{{Subject: pkix.Name{CommonName: "d"}}}}) - c.Assert(err, NotNil) -} - -func (ts *HTTPHandlerTestSuite) TestFailpointHandler(c *C) { - defer ts.stopServer(c) - - // start server without enabling failpoint integration - ts.startServer(c) - resp, err := ts.fetchStatus("/fail/") - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusNotFound) - c.Assert(resp.Body.Close(), IsNil) - ts.stopServer(c) - - // enable failpoint integration and start server - c.Assert(failpoint.Enable("github.com/pingcap/tidb/server/enableTestAPI", "return"), IsNil) - ts.startServer(c) - resp, err = ts.fetchStatus("/fail/") - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusOK) - b, err := io.ReadAll(resp.Body) - c.Assert(err, IsNil) - c.Assert(strings.Contains(string(b), "github.com/pingcap/tidb/server/enableTestAPI=return"), IsTrue) - c.Assert(resp.Body.Close(), IsNil) -} - -func (ts *HTTPHandlerTestSuite) TestTestHandler(c *C) { - defer ts.stopServer(c) - - // start server without enabling failpoint integration - ts.startServer(c) - resp, err := ts.fetchStatus("/test") - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusNotFound) - c.Assert(resp.Body.Close(), IsNil) - ts.stopServer(c) - - // enable failpoint integration and start server - c.Assert(failpoint.Enable("github.com/pingcap/tidb/server/enableTestAPI", "return"), IsNil) - ts.startServer(c) - - resp, err = ts.fetchStatus("/test/gc/gc") - c.Assert(err, IsNil) - err = resp.Body.Close() - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) - - resp, err = ts.fetchStatus("/test/gc/resolvelock") - c.Assert(err, IsNil) - err = resp.Body.Close() - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) - - resp, err = ts.fetchStatus("/test/gc/resolvelock?safepoint=a") - c.Assert(err, IsNil) - err = resp.Body.Close() - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) - - resp, err = ts.fetchStatus("/test/gc/resolvelock?physical=1") - c.Assert(err, IsNil) - err = resp.Body.Close() - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) - - resp, err = ts.fetchStatus("/test/gc/resolvelock?physical=true") - c.Assert(err, IsNil) - err = resp.Body.Close() - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) - - resp, err = ts.fetchStatus("/test/gc/resolvelock?safepoint=10000&physical=true") - c.Assert(err, IsNil) - err = resp.Body.Close() - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusOK) + require.Error(t, err) } -func (ts *HTTPHandlerTestSuite) TestDDLHookHandler(c *C) { - defer ts.stopServer(c) +func TestDDLHookHandler(t *testing.T) { + t.Parallel() + ts := createBasicHTTPHandlerTestSuite() - ts.startServer(c) + ts.startServer(t) + defer ts.stopServer(t) resp, err := ts.fetchStatus("/test/ddl/hook") - c.Assert(err, IsNil) - c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) - c.Assert(resp.Body.Close(), IsNil) + require.NoError(t, err) + require.Equal(t, http.StatusBadRequest, resp.StatusCode) + require.NoError(t, resp.Body.Close()) resp, err = ts.postStatus("/test/ddl/hook", "application/x-www-form-urlencoded", bytes.NewBuffer([]byte(`ddl_hook=ctc_hook`))) - c.Assert(err, IsNil) - c.Assert(resp, NotNil) + require.NoError(t, err) + require.NotNil(t, resp) body, err := io.ReadAll(resp.Body) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(string(body), Equals, "\"success!\"") - c.Assert(resp.StatusCode, Equals, http.StatusOK) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, "\"success!\"", string(body)) + require.Equal(t, http.StatusOK, resp.StatusCode) resp, err = ts.postStatus("/test/ddl/hook", "application/x-www-form-urlencoded", bytes.NewBuffer([]byte(`ddl_hook=default_hook`))) - c.Assert(err, IsNil) - c.Assert(resp, NotNil) + require.NoError(t, err) + require.NotNil(t, resp) body, err = io.ReadAll(resp.Body) - c.Assert(err, IsNil) - c.Assert(resp.Body.Close(), IsNil) - c.Assert(string(body), Equals, "\"success!\"") - c.Assert(resp.StatusCode, Equals, http.StatusOK) + require.NoError(t, err) + require.NoError(t, resp.Body.Close()) + require.Equal(t, "\"success!\"", string(body)) + require.Equal(t, http.StatusOK, resp.StatusCode) } diff --git a/server/main_test.go b/server/main_test.go index a7fd224a9f130..4c3969da1f506 100644 --- a/server/main_test.go +++ b/server/main_test.go @@ -15,15 +15,36 @@ package server import ( + "fmt" + "os" + "reflect" "testing" + "github.com/pingcap/tidb/config" + "github.com/pingcap/tidb/session" "github.com/pingcap/tidb/util/testbridge" + "github.com/tikv/client-go/v2/tikv" "go.uber.org/goleak" ) func TestMain(m *testing.M) { testbridge.WorkaroundGoCheckFlags() + // AsyncCommit will make DDL wait 2.5s before changing to the next state. + // Set schema lease to avoid it from making CI slow. + session.SetSchemaLease(0) + + tikv.EnableFailpoints() + + // sanity check: the global config should not be changed by other pkg init function. + // see also https://github.com/pingcap/tidb/issues/22162 + defaultConfig := config.NewConfig() + globalConfig := config.GetGlobalConfig() + if !reflect.DeepEqual(defaultConfig, globalConfig) { + _, _ = fmt.Fprintf(os.Stderr, "server: the global config has been changed.\n") + _, _ = fmt.Fprintf(os.Stderr, "default: %#v\nglobal: %#v", defaultConfig, globalConfig) + } + opts := []goleak.Option{ goleak.IgnoreTopFunction("time.Sleep"), goleak.IgnoreTopFunction("database/sql.(*Tx).awaitDone"), diff --git a/server/server_test.go b/server/server_test.go index f34651791d545..82e4dd6ab883e 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -25,7 +25,6 @@ import ( "net/url" "os" "path/filepath" - "reflect" "regexp" "strconv" "strings" @@ -37,14 +36,10 @@ import ( "github.com/pingcap/errors" "github.com/pingcap/failpoint" "github.com/pingcap/log" - "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/errno" "github.com/pingcap/tidb/kv" tmysql "github.com/pingcap/tidb/parser/mysql" - "github.com/pingcap/tidb/session" - "github.com/pingcap/tidb/util/logutil" "github.com/pingcap/tidb/util/versioninfo" - "github.com/tikv/client-go/v2/tikv" "go.uber.org/zap" ) @@ -53,23 +48,7 @@ var ( ) func TestT(t *testing.T) { - defaultConfig := config.NewConfig() - globalConfig := config.GetGlobalConfig() - // Test for issue 22162. the global config shouldn't be changed by other pkg init function. - if !reflect.DeepEqual(defaultConfig, globalConfig) { - t.Fatalf("%#v != %#v\n", defaultConfig, globalConfig) - } - - // AsyncCommit will make DDL wait 2.5s before changing to the next state. - // Set schema lease to avoid it from making CI slow. - session.SetSchemaLease(0) CustomVerboseFlag = true - logLevel := os.Getenv("log_level") - err := logutil.InitLogger(logutil.NewLogConfig(logLevel, logutil.DefaultLogFormat, "", logutil.EmptyFileLogConfig, false)) - if err != nil { - t.Fatal(err) - } - tikv.EnableFailpoints() TestingT(t) } diff --git a/testkit/dbtestkit.go b/testkit/dbtestkit.go index b0039098a48ae..1de971bf3a34c 100644 --- a/testkit/dbtestkit.go +++ b/testkit/dbtestkit.go @@ -58,3 +58,8 @@ func (tk *DBTestKit) MustQuery(sql string, args ...interface{}) *sql.Rows { tk.require.NotNil(rows, comment) return rows } + +// GetDB returns the underlay sql.DB instance. +func (tk *DBTestKit) GetDB() *sql.DB { + return tk.db +}