From 295e8dfd61f967b4eefcf07a2c0d2878ae28da99 Mon Sep 17 00:00:00 2001 From: maxshuang Date: Thu, 3 Mar 2022 00:18:21 +0800 Subject: [PATCH 01/19] feat(tester): add reserve-schema option to avoid drop schema after each test case (#55) --- README.md | 2 ++ src/main.go | 24 ++++++++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index dc0a81e..3b8e722 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,8 @@ Usage of ./mysql-tester: The listen port of TiDB/MySQL server. (default "4000") -record Whether to record the test output to the result file. + -reserve-schema + Reserve schema after each test -user string The user for connecting to the database. (default "root") ``` diff --git a/src/main.go b/src/main.go index a4eb961..74dec06 100644 --- a/src/main.go +++ b/src/main.go @@ -37,15 +37,16 @@ import ( ) var ( - wg sync.WaitGroup - host string - port string - user string - passwd string - logLevel string - record bool - params string - all bool + wg sync.WaitGroup + host string + port string + user string + passwd string + logLevel string + record bool + params string + all bool + reserveSchema bool ) func init() { @@ -57,6 +58,7 @@ func init() { flag.BoolVar(&record, "record", false, "Whether to record the test output to the result file.") flag.StringVar(¶ms, "params", "", "Additional params pass as DSN(e.g. session variable)") flag.BoolVar(&all, "all", false, "run all tests") + flag.BoolVar(&reserveSchema, "reserve-schema", false, "Reserve schema after each test") c := &charset.Charset{ Name: "gbk", @@ -243,7 +245,9 @@ func (t *tester) preProcess() { } func (t *tester) postProcess() { - t.mdb.Exec(fmt.Sprintf("drop database `%s`", t.name)) + if !reserveSchema { + t.mdb.Exec(fmt.Sprintf("drop database `%s`", t.name)) + } for _, v := range t.conn { v.mdb.Close() } From 088f11aaaf463f4e8e6f18f3a0c6e298f6de164b Mon Sep 17 00:00:00 2001 From: CbcWestwolf <1004626265@qq.com> Date: Wed, 16 Mar 2022 16:15:50 +0800 Subject: [PATCH 02/19] Add formatted output xml (#56) --- src/main.go | 109 +++++++++++++++++++++++++++++++++++++++++++++------- src/xml.go | 93 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+), 14 deletions(-) create mode 100644 src/xml.go diff --git a/src/main.go b/src/main.go index 74dec06..438bcb3 100644 --- a/src/main.go +++ b/src/main.go @@ -47,6 +47,7 @@ var ( params string all bool reserveSchema bool + xmlPath string ) func init() { @@ -59,6 +60,7 @@ func init() { flag.StringVar(¶ms, "params", "", "Additional params pass as DSN(e.g. session variable)") flag.BoolVar(&all, "all", false, "run all tests") flag.BoolVar(&reserveSchema, "reserve-schema", false, "Reserve schema after each test") + flag.StringVar(&xmlPath, "xunitfile", "", "The xml file path to record testing results.") c := &charset.Charset{ Name: "gbk", @@ -253,16 +255,40 @@ func (t *tester) postProcess() { } } +func (t *tester) addFailure(testSuite *XUnitTestSuite, err *error, cnt int) { + testSuite.TestCases = append(testSuite.TestCases, XUnitTestCase{ + Classname: "", + Name: t.testFileName(), + Time: "", + QueryCount: cnt, + Failure: (*err).Error(), + }) + testSuite.Failures++ +} + +func (t *tester) addSuccess(testSuite *XUnitTestSuite, startTime *time.Time, cnt int) { + testSuite.TestCases = append(testSuite.TestCases, XUnitTestCase{ + Classname: "", + Name: t.testFileName(), + Time: fmt.Sprintf("%fs", time.Since(*startTime).Seconds()), + QueryCount: cnt, + }) +} + func (t *tester) Run() error { t.preProcess() defer t.postProcess() queries, err := t.loadQueries() if err != nil { - return errors.Trace(err) + err = errors.Trace(err) + t.addFailure(&testSuite, &err, 0) + return err } if err = t.openResult(); err != nil { - return errors.Trace(err) + err = errors.Trace(err) + t.addFailure(&testSuite, &err, 0) + return err } var s string @@ -302,13 +328,17 @@ func (t *tester) Run() error { } else { concurrentSize, err = strconv.Atoi(strings.TrimSpace(s)) if err != nil { - return errors.Annotate(err, "Atoi failed") + err = errors.Annotate(err, "Atoi failed") + t.addFailure(&testSuite, &err, testCnt) + return err } } case Q_END_CONCURRENT: t.enableConcurrent = false if err = t.concurrentRun(concurrentQueue, concurrentSize); err != nil { - return errors.Annotate(err, fmt.Sprintf("concurrent test failed in %v", t.name)) + err = errors.Annotate(err, fmt.Sprintf("concurrent test failed in %v", t.name)) + t.addFailure(&testSuite, &err, testCnt) + return err } t.expectedErrs = nil case Q_ERROR: @@ -320,7 +350,9 @@ func (t *tester) Run() error { if t.enableConcurrent { concurrentQueue = append(concurrentQueue, q) } else if err = t.execute(q); err != nil { - return errors.Annotate(err, fmt.Sprintf("sql:%v", q.Query)) + err = errors.Annotate(err, fmt.Sprintf("sql:%v", q.Query)) + t.addFailure(&testSuite, &err, testCnt) + return err } testCnt++ @@ -337,7 +369,9 @@ func (t *tester) Run() error { for i := 0; i < len(cols)-1; i = i + 2 { colNr, err := strconv.Atoi(cols[i]) if err != nil { - return errors.Annotate(err, fmt.Sprintf("Could not parse column in --replace_column: sql:%v", q.Query)) + err = errors.Annotate(err, fmt.Sprintf("Could not parse column in --replace_column: sql:%v", q.Query)) + t.addFailure(&testSuite, &err, testCnt) + return err } t.replaceColumn = append(t.replaceColumn, ReplaceColumn{col: colNr, replace: []byte(cols[i+1])}) @@ -373,6 +407,10 @@ func (t *tester) Run() error { fmt.Printf("%s: ok! %d test cases passed, take time %v s\n", t.testFileName(), testCnt, time.Since(startTime).Seconds()) + if xmlPath != "" { + t.addSuccess(&testSuite, &startTime, testCnt) + } + return t.flushResult() } @@ -935,6 +973,8 @@ func convertTestsToTestTasks(tests []string) (tTasks []testBatch, have_show, hav } var msgs = make(chan testTask) +var xmlFile *os.File +var testSuite XUnitTestSuite type testTask struct { err error @@ -991,15 +1031,11 @@ func consumeError() []error { if t, more := <-msgs; more { if t.err != nil { e := fmt.Errorf("run test [%s] err: %v", t.test, t.err) - if !all { - log.Fatalln(e) - } log.Errorln(e) es = append(es, e) } else { log.Infof("run test [%s] ok", t.test) } - } else { return es } @@ -1009,6 +1045,52 @@ func consumeError() []error { func main() { flag.Parse() tests := flag.Args() + startTime := time.Now() + + if xmlPath != "" { + _, err := os.Stat(xmlPath) + if err == nil { + err = os.Remove(xmlPath) + if err != nil { + log.Errorf("drop previous xunit file fail: ", err) + os.Exit(1) + } + } + + xmlFile, err = os.Create(xmlPath) + if err != nil { + log.Errorf("create xunit file fail:", err) + os.Exit(1) + } + xmlFile, err = os.OpenFile(xmlPath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) + if err != nil { + log.Errorf("open xunit file fail:", err) + os.Exit(1) + } + + testSuite = XUnitTestSuite{ + Name: "", + Tests: 0, + Failures: 0, + Properties: make([]XUnitProperty, 0), + TestCases: make([]XUnitTestCase, 0), + } + + defer func() { + if xmlFile != nil { + testSuite.Tests = len(tests) + testSuite.Time = fmt.Sprintf("%fs", time.Since(startTime).Seconds()) + testSuite.Properties = append(testSuite.Properties, XUnitProperty{ + Name: "go.version", + Value: goVersion(), + }) + err := Write(xmlFile, testSuite) + if err != nil { + log.Errorf("Write xunit file fail:", err) + } + } + }() + } // we will run all tests if no tests assigned if len(tests) == 0 { @@ -1030,14 +1112,13 @@ func main() { }() es := consumeError() + println() if len(es) != 0 { - println() log.Errorf("%d tests failed\n", len(es)) for _, item := range es { log.Errorln(item) } - os.Exit(1) + } else { + println("Great, All tests passed") } - - println("\nGreat, All tests passed") } diff --git a/src/xml.go b/src/xml.go new file mode 100644 index 0000000..12f453a --- /dev/null +++ b/src/xml.go @@ -0,0 +1,93 @@ +// Copyright 2020 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, +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "encoding/xml" + log "github.com/sirupsen/logrus" + "io" + "os" + "os/exec" + "strings" +) + +// XUnitTestSuites is a set of mysqltest suite. +type XUnitTestSuites struct { + XMLName xml.Name `xml:"testsuites"` + Suites []XUnitTestSuite +} + +// XUnitTestSuite is a single mysqltest suite which may contain many +// testcases in a directory +type XUnitTestSuite struct { + XMLName xml.Name `xml:"testsuite"` + Tests int `xml:"tests,attr"` + Failures int `xml:"failures,attr"` + Name string `xml:"name,attr"` + Time string `xml:"time,attr"` + Properties []XUnitProperty `xml:"properties>property,omitempty"` + TestCases []XUnitTestCase +} + +// XUnitTestCase is a single test case with its result. +type XUnitTestCase struct { + XMLName xml.Name `xml:"testcase"` + Classname string `xml:"classname,attr"` + Name string `xml:"name,attr"` + Time string `xml:"time,attr"` + QueryCount int `xml:"query-count,attr"` + Failure string `xml:"failure,omitempty"` +} + +// XUnitProperty represents a key/value pair used to define properties. +type XUnitProperty struct { + Name string `xml:"name,attr"` + Value string `xml:"value,attr"` +} + +func Write(out io.Writer, testSuite XUnitTestSuite) error { + testSuites := XUnitTestSuites{ + Suites: make([]XUnitTestSuite, 0), + } + testSuites.Suites = append(testSuites.Suites, testSuite) + _, err := out.Write([]byte(xml.Header)) + if err != nil { + log.Errorf("write xunit file fail:", err) + return err + } + doc, err := xml.MarshalIndent(testSuites, "", "\t") + if err != nil { + return err + } + _, err = out.Write(doc) + return err +} + +// goVersion returns the version as reported by the go binary in PATH. This +// version will not be the same as runtime.Version, which is always the version +// of go used to build the gotestsum binary. +// +// To skip the os/exec call set the GOVERSION environment variable to the +// desired value. +func goVersion() string { + if version, ok := os.LookupEnv("GOVERSION"); ok { + return version + } + cmd := exec.Command("go", "version") + out, err := cmd.Output() + if err != nil { + return "unknown" + } + return strings.TrimPrefix(strings.TrimSpace(string(out)), "go version ") +} From fdd6486b19ca76c6164281eea7584b8aeafaebb4 Mon Sep 17 00:00:00 2001 From: CbcWestwolf <1004626265@qq.com> Date: Sat, 7 May 2022 14:33:32 +0800 Subject: [PATCH 03/19] Fix mysql-tester failure with exit code 0. (#58) --- src/main.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main.go b/src/main.go index 438bcb3..8034e89 100644 --- a/src/main.go +++ b/src/main.go @@ -1118,6 +1118,8 @@ func main() { for _, item := range es { log.Errorln(item) } + // Can't delete this statement. + os.Exit(1) } else { println("Great, All tests passed") } From 8ab0c70d9e917c7626406651c143dddf491610f8 Mon Sep 17 00:00:00 2001 From: Yiding Cui Date: Tue, 10 May 2022 10:20:19 +0800 Subject: [PATCH 04/19] *: let the client can read file so we can use `LOAD STATS` (#60) --- src/main.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.go b/src/main.go index 8034e89..ea7123d 100644 --- a/src/main.go +++ b/src/main.go @@ -170,7 +170,7 @@ func isTiDB(db *sql.DB) bool { } func (t *tester) addConnection(connName, hostName, userName, password, db string) { - mdb, err := OpenDBWithRetry("mysql", userName+":"+password+"@tcp("+hostName+":"+port+")/"+db+"?time_zone=%27Asia%2FShanghai%27"+params) + mdb, err := OpenDBWithRetry("mysql", userName+":"+password+"@tcp("+hostName+":"+port+")/"+db+"?time_zone=%27Asia%2FShanghai%27&allowAllFiles=true"+params) if err != nil { log.Fatalf("Open db err %v", err) } @@ -217,7 +217,7 @@ func (t *tester) disconnect(connName string) { func (t *tester) preProcess() { dbName := "test" - mdb, err := OpenDBWithRetry("mysql", user+":"+passwd+"@tcp("+host+":"+port+")/"+dbName+"?time_zone=%27Asia%2FShanghai%27"+params) + mdb, err := OpenDBWithRetry("mysql", user+":"+passwd+"@tcp("+host+":"+port+")/"+dbName+"?time_zone=%27Asia%2FShanghai%27&allowAllFiles=true"+params) t.conn = make(map[string]*Conn) if err != nil { log.Fatalf("Open db err %v", err) @@ -451,7 +451,7 @@ func (t *tester) concurrentExecute(querys []query, wg *sync.WaitGroup, errOccure defer wg.Done() tt := newTester(t.name) dbName := "test" - mdb, err := OpenDBWithRetry("mysql", user+":"+passwd+"@tcp("+host+":"+port+")/"+dbName+"?time_zone=%27Asia%2FShanghai%27"+params) + mdb, err := OpenDBWithRetry("mysql", user+":"+passwd+"@tcp("+host+":"+port+")/"+dbName+"?time_zone=%27Asia%2FShanghai%27&allowAllFiles=true"+params) if err != nil { log.Fatalf("Open db err %v", err) } From b5facdcdf72e4efbfa648611ec58ddc624eaa97a Mon Sep 17 00:00:00 2001 From: Song Gao Date: Wed, 25 May 2022 19:32:39 +0800 Subject: [PATCH 05/19] set session vars to avoid explain fail cases(#61) --- .gitignore | 28 ++++++++++++++++++++++++++++ src/main.go | 11 +++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5883d18 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### Vscode files ### +.vscode/** + +### MAC ### +.DS_Store diff --git a/src/main.go b/src/main.go index ea7123d..c646f4c 100644 --- a/src/main.go +++ b/src/main.go @@ -154,10 +154,13 @@ func newTester(name string) *tester { return t } -func setHashJoinConcurrency(db *sql.DB) { +func setSessionVariable(db *sql.DB) { if _, err := db.Exec("SET @@tidb_hash_join_concurrency=1"); err != nil { log.Fatalf("Executing \"SET @@tidb_hash_join_concurrency=1\" err[%v]", err) } + if _, err := db.Exec("SET @@tidb_enable_pseudo_for_outdated_stats=false"); err != nil { + log.Fatalf("Executing \"SET @@tidb_enable_pseudo_for_outdated_stats=false\" err[%v]", err) + } } // isTiDB returns true if the DB is confirmed to be TiDB @@ -181,7 +184,7 @@ func (t *tester) addConnection(connName, hostName, userName, password, db string if _, err = mdb.Exec("SET @@tidb_max_chunk_size=32"); err != nil { log.Fatalf("Executing \"SET @@tidb_max_chunk_size=32\" err[%v]", err) } - setHashJoinConcurrency(mdb) + setSessionVariable(mdb) } t.conn[connName] = &Conn{mdb: mdb, tx: nil} t.switchConnection(connName) @@ -239,7 +242,7 @@ func (t *tester) preProcess() { if _, err = mdb.Exec("SET @@tidb_max_chunk_size=32"); err != nil { log.Fatalf("Executing \"SET @@tidb_max_chunk_size=32\" err[%v]", err) } - setHashJoinConcurrency(mdb) + setSessionVariable(mdb) } t.mdb = mdb t.conn[default_connection] = &Conn{mdb: mdb, tx: nil} @@ -465,7 +468,7 @@ func (t *tester) concurrentExecute(querys []query, wg *sync.WaitGroup, errOccure if _, err = mdb.Exec("SET @@tidb_max_chunk_size=32"); err != nil { log.Fatalf("Executing \"SET @@tidb_max_chunk_size=32\" err[%v]", err) } - setHashJoinConcurrency(mdb) + setSessionVariable(mdb) } tt.mdb = mdb defer tt.mdb.Close() From 2332826489d4f6957d60918598803ef1565f00c9 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Thu, 26 May 2022 12:26:09 +0800 Subject: [PATCH 06/19] try no concurrency test (#62) --- src/main.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main.go b/src/main.go index c646f4c..39403da 100644 --- a/src/main.go +++ b/src/main.go @@ -37,7 +37,6 @@ import ( ) var ( - wg sync.WaitGroup host string port string user string @@ -987,7 +986,6 @@ type testTask struct { type testBatch []string func (t testBatch) Run() { - defer wg.Done() for _, test := range t { tr := newTester(test) msgs <- testTask{ @@ -1020,12 +1018,9 @@ func executeTests(tasks []testBatch, have_show, have_is bool) { } } - wg.Add(len(tasks)) for _, t := range tasks { - go t.Run() + t.Run() } - - wg.Wait() } func consumeError() []error { From 044fec6fa6c79039dc532c74968a06112931cb6d Mon Sep 17 00:00:00 2001 From: crazycs Date: Mon, 6 Jun 2022 13:33:50 +0800 Subject: [PATCH 07/19] tiny change for support savepoint (#59) --- go.mod | 8 +++++--- go.sum | 41 +++++++++++++++++++++++-------------- src/main.go | 59 +++++++++++++++++++++++++++-------------------------- 3 files changed, 61 insertions(+), 47 deletions(-) diff --git a/go.mod b/go.mod index 130d1ee..0c0046f 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,15 @@ module github.com/pingcap/mysql-tester go 1.12 require ( + github.com/benbjohnson/clock v1.3.0 // indirect github.com/go-sql-driver/mysql v1.6.0 github.com/pingcap/errors v0.11.5-0.20211009033009-93128226aaa3 - github.com/pingcap/log v0.0.0-20210906054005-afc726e70354 // indirect - github.com/pingcap/tidb/parser v0.0.0-20211122065349-4d16aabf900b + github.com/pingcap/log v1.1.0 // indirect + github.com/pingcap/tidb/parser v0.0.0-20220603021027-173dd005cc34 github.com/pkg/errors v0.9.1 // indirect github.com/sirupsen/logrus v1.8.1 - go.uber.org/zap v1.19.1 // indirect + go.uber.org/multierr v1.8.0 // indirect + go.uber.org/zap v1.21.0 // indirect golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 // indirect golang.org/x/text v0.3.7 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect diff --git a/go.sum b/go.sum index 5a8123f..62695f5 100644 --- a/go.sum +++ b/go.sum @@ -1,14 +1,11 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/cznic/golex v0.0.0-20181122101858-9c343928389c/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc= -github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= -github.com/cznic/parser v0.0.0-20160622100904-31edd927e5b1/go.mod h1:2B43mz36vGZNZEwkWi8ayRSSUXLfjL8OkbzwW4NcPMM= github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc= -github.com/cznic/y v0.0.0-20170802143616-045f81c6662a/go.mod h1:1rk5VM7oSnA4vjp+hrLQ3HWHa+Y4yPCa3/CsJrcNnvs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -24,16 +21,15 @@ github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63/go.mod h1:X2r9ue github.com/pingcap/errors v0.11.5-0.20211009033009-93128226aaa3 h1:8l9lu9RjWkI/VeqrP+Fn3tvZNPu5GYP0rYLLN5Q46go= github.com/pingcap/errors v0.11.5-0.20211009033009-93128226aaa3/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg= github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7/go.mod h1:8AanEdAHATuRurdGxZXBz0At+9avep+ub7U1AGYLIMM= -github.com/pingcap/log v0.0.0-20210906054005-afc726e70354 h1:SvWCbCPh1YeHd9yQLksvJYAgft6wLTY1aNG81tpyscQ= -github.com/pingcap/log v0.0.0-20210906054005-afc726e70354/go.mod h1:DWQW5jICDR7UJh4HtxXSM20Churx4CQL0fwL/SoOSA4= -github.com/pingcap/tidb/parser v0.0.0-20211122065349-4d16aabf900b h1:FogJmQ1Qx133lg3G9U/WWRZMmfjwl7Y3D1qbuHW1CFk= -github.com/pingcap/tidb/parser v0.0.0-20211122065349-4d16aabf900b/go.mod h1:MAa22tagoj7nv5b1NBcxPkc5CiUNhqj1wuSQnw4f9WE= +github.com/pingcap/log v1.1.0 h1:ELiPxACz7vdo1qAvvaWJg1NrYFoY6gqAh/+Uo6aXdD8= +github.com/pingcap/log v1.1.0/go.mod h1:DWQW5jICDR7UJh4HtxXSM20Churx4CQL0fwL/SoOSA4= +github.com/pingcap/tidb/parser v0.0.0-20220603021027-173dd005cc34 h1:fV94RTFxPv5k2lmsWL4fUEjlO7ps36cFP/uRNl+W3Zo= +github.com/pingcap/tidb/parser v0.0.0-20220603021027-173dd005cc34/go.mod h1:ElJiub4lRy6UZDb+0JHDkGEdr6aOli+ykhyej7VCLoI= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= @@ -50,19 +46,21 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= @@ -110,3 +108,16 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8= +modernc.org/golex v1.0.1/go.mod h1:QCA53QtsT1NdGkaZZkF5ezFwk4IXh4BGNafAARTC254= +modernc.org/lex v1.0.0/go.mod h1:G6rxMTy3cH2iA0iXL/HRRv4Znu8MK4higxph/lE7ypk= +modernc.org/lexer v1.0.0/go.mod h1:F/Dld0YKYdZCLQ7bD0USbWL4YKCyTDRDHiDTOs0q0vk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/parser v1.0.0/go.mod h1:H20AntYJ2cHHL6MHthJ8LZzXCdDCHMWt1KZXtIMjejA= +modernc.org/parser v1.0.2/go.mod h1:TXNq3HABP3HMaqLK7brD1fLA/LfN0KS6JxZn71QdDqs= +modernc.org/scanner v1.0.1/go.mod h1:OIzD2ZtjYk6yTuyqZr57FmifbM9fIH74SumloSsajuE= +modernc.org/sortutil v1.0.0/go.mod h1:1QO0q8IlIlmjBIwm6t/7sof874+xCfZouyqZMLIAtxM= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/y v1.0.1/go.mod h1:Ho86I+LVHEI+LYXoUKlmOMAM1JTXOCfj8qi1T8PsClE= diff --git a/src/main.go b/src/main.go index 39403da..991d545 100644 --- a/src/main.go +++ b/src/main.go @@ -624,51 +624,49 @@ func (t *tester) stmtExecute(query query, st ast.StmtNode) (err error) { t.buf.WriteString(qText) t.buf.WriteString("\n") } - switch st.(type) { + switch x := st.(type) { case *ast.BeginStmt: t.tx, err = t.mdb.Begin() if err != nil { t.rollback() - break } + return err case *ast.CommitStmt: err = t.commit() if err != nil { t.rollback() - break } + return err case *ast.RollbackStmt: - err = t.rollback() + if x.SavepointName == "" { + return t.rollback() + } + } + if t.tx != nil { + err = t.executeStmt(qText) if err != nil { - break + return err } - default: - if t.tx != nil { - err = t.executeStmt(qText) - if err != nil { - break - } + } else { + // if begin or the succeeding commit fails, we don't think + // this error is the expected one. + if t.tx, err = t.mdb.Begin(); err != nil { + t.rollback() + return err + } + + err = t.executeStmt(qText) + if err != nil { + t.rollback() + return err } else { - // if begin or following commit fails, we don't think - // this error is the expected one. - if t.tx, err = t.mdb.Begin(); err != nil { - t.rollback() - break + commitErr := t.commit() + if err == nil && commitErr != nil { + err = commitErr } - - err = t.executeStmt(qText) - if err != nil { + if commitErr != nil { t.rollback() - break - } else { - commitErr := t.commit() - if err == nil && commitErr != nil { - err = commitErr - } - if commitErr != nil { - t.rollback() - break - } + return err } } } @@ -723,6 +721,9 @@ func (t *tester) execute(query query) error { } func (t *tester) commit() error { + if t.tx == nil { + return nil + } err := t.tx.Commit() if err != nil { return err From 3c5b9aaba0ac7746cb91186aa8982d22aaa3a5ef Mon Sep 17 00:00:00 2001 From: wjHuang Date: Fri, 5 Aug 2022 12:58:58 +0800 Subject: [PATCH 08/19] src: enlarge open db timeout (#74) --- src/util.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util.go b/src/util.go index 9d88230..f098e7c 100644 --- a/src/util.go +++ b/src/util.go @@ -27,8 +27,8 @@ import ( func OpenDBWithRetry(driverName, dataSourceName string) (mdb *sql.DB, err error) { startTime := time.Now() sleepTime := time.Millisecond * 500 - retryCnt := 60 - // The max retry interval is 30 s. + retryCnt := 120 + // The max retry interval is 60 s. for i := 0; i < retryCnt; i++ { mdb, err = sql.Open(driverName, dataSourceName) if err != nil { From 39d06e0f73a9fd7a2a4a5c6dc86a82d59aad9ae1 Mon Sep 17 00:00:00 2001 From: wjHuang Date: Tue, 9 Aug 2022 15:13:45 +0800 Subject: [PATCH 09/19] src: support trace statement (#75) --- src/util.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/util.go b/src/util.go index f098e7c..38a4619 100644 --- a/src/util.go +++ b/src/util.go @@ -52,8 +52,7 @@ func OpenDBWithRetry(driverName, dataSourceName string) (mdb *sql.DB, err error) return } -// copied from https://github.com/pingcap/tidb/blob/4995fe741ea527b3870731a6873d34a92403d3de/cmd/explaintest/main.go#L699 -var queryStmtTable = []string{"explain", "select", "show", "execute", "describe", "desc", "admin", "with"} +var queryStmtTable = []string{"explain", "select", "show", "execute", "describe", "desc", "admin", "with", "trace"} func trimSQL(sql string) string { // Trim space. From e8db203cca1ab4023072d6195d758ad02f061d8f Mon Sep 17 00:00:00 2001 From: Song Gao Date: Thu, 18 Aug 2022 17:08:29 +0800 Subject: [PATCH 10/19] set tidb_enable_analyze_snapshot druing test (#77) --- src/main.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.go b/src/main.go index 991d545..7f7363a 100644 --- a/src/main.go +++ b/src/main.go @@ -160,6 +160,10 @@ func setSessionVariable(db *sql.DB) { if _, err := db.Exec("SET @@tidb_enable_pseudo_for_outdated_stats=false"); err != nil { log.Fatalf("Executing \"SET @@tidb_enable_pseudo_for_outdated_stats=false\" err[%v]", err) } + // enable tidb_enable_analyze_snapshot in order to let analyze request with SI isolation level to get accurate response + if _, err := db.Exec("SET @@tidb_enable_analyze_snapshot=1"); err != nil { + log.Fatalf("Executing \"SET @@tidb_enable_analyze_snapshot=1\" err[%v]", err) + } } // isTiDB returns true if the DB is confirmed to be TiDB From 32bc9220897e68de38c18ed60c2f84ebca6c0682 Mon Sep 17 00:00:00 2001 From: CbcWestwolf <1004626265@qq.com> Date: Thu, 18 Aug 2022 21:04:40 +0800 Subject: [PATCH 11/19] Receive error when trying to connect. (#76) --- README.md | 10 +++++++++- src/main.go | 27 ++++++++++++++++----------- src/util.go | 7 +++---- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 3b8e722..8f78f77 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,14 @@ make Basic usage: ``` Usage of ./mysql-tester: + -all + run all tests -host string The host of the TiDB/MySQL server. (default "127.0.0.1") -log-level string The log level of mysql-tester: info, warn, error, debug. (default "error") + -params string + Additional params pass as DSN(e.g. session variable) -passwd string The password for the user. -port string @@ -28,9 +32,13 @@ Usage of ./mysql-tester: -record Whether to record the test output to the result file. -reserve-schema - Reserve schema after each test + Reserve schema after each test + -retry-connection-count int + The max number to retry to connect to the database. (default 120) -user string The user for connecting to the database. (default "root") + -xunitfile string + The xml file path to record testing results. ``` By default, it connects to the TiDB/MySQL server at `127.0.0.1:4000` with `root` and no passward: diff --git a/src/main.go b/src/main.go index 7f7363a..e0c69ce 100644 --- a/src/main.go +++ b/src/main.go @@ -37,16 +37,17 @@ import ( ) var ( - host string - port string - user string - passwd string - logLevel string - record bool - params string - all bool - reserveSchema bool - xmlPath string + host string + port string + user string + passwd string + logLevel string + record bool + params string + all bool + reserveSchema bool + xmlPath string + retryConnCount int ) func init() { @@ -60,6 +61,7 @@ func init() { flag.BoolVar(&all, "all", false, "run all tests") flag.BoolVar(&reserveSchema, "reserve-schema", false, "Reserve schema after each test") flag.StringVar(&xmlPath, "xunitfile", "", "The xml file path to record testing results.") + flag.IntVar(&retryConnCount, "retry-connection-count", 120, "The max number to retry to connect to the database.") c := &charset.Charset{ Name: "gbk", @@ -178,7 +180,10 @@ func isTiDB(db *sql.DB) bool { func (t *tester) addConnection(connName, hostName, userName, password, db string) { mdb, err := OpenDBWithRetry("mysql", userName+":"+password+"@tcp("+hostName+":"+port+")/"+db+"?time_zone=%27Asia%2FShanghai%27&allowAllFiles=true"+params) if err != nil { - log.Fatalf("Open db err %v", err) + if t.expectedErrs == nil { + log.Fatalf("Open db err %v", err) + } + return } if isTiDB(mdb) { if _, err = mdb.Exec("SET @@tidb_init_chunk_size=1"); err != nil { diff --git a/src/util.go b/src/util.go index 38a4619..aa082ec 100644 --- a/src/util.go +++ b/src/util.go @@ -27,12 +27,11 @@ import ( func OpenDBWithRetry(driverName, dataSourceName string) (mdb *sql.DB, err error) { startTime := time.Now() sleepTime := time.Millisecond * 500 - retryCnt := 120 // The max retry interval is 60 s. - for i := 0; i < retryCnt; i++ { + for i := 0; i < retryConnCount; i++ { mdb, err = sql.Open(driverName, dataSourceName) if err != nil { - log.Warnf("open db failed, retry count %d err %v", i, err) + log.Warnf("open db failed, retry count %d (remain %d) err %v", i, retryConnCount-i, err) time.Sleep(sleepTime) continue } @@ -40,7 +39,7 @@ func OpenDBWithRetry(driverName, dataSourceName string) (mdb *sql.DB, err error) if err == nil { break } - log.Warnf("ping db failed, retry count %d err %v", i, err) + log.Warnf("ping db failed, retry count %d (remain %d) err %v", i, retryConnCount-i, err) mdb.Close() time.Sleep(sleepTime) } From e7ff64608125929e6ba6b70f40d149c1354f7c93 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Fri, 19 Aug 2022 20:40:41 +0800 Subject: [PATCH 12/19] check tidb version for tidb_enable_analyze_snapshot (#78) --- go.mod | 1 + go.sum | 2 ++ src/main.go | 41 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0c0046f..0796a71 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.12 require ( github.com/benbjohnson/clock v1.3.0 // indirect + github.com/coreos/go-semver v0.3.0 github.com/go-sql-driver/mysql v1.6.0 github.com/pingcap/errors v0.11.5-0.20211009033009-93128226aaa3 github.com/pingcap/log v1.1.0 // indirect diff --git a/go.sum b/go.sum index 62695f5..a6691e2 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc= diff --git a/src/main.go b/src/main.go index e0c69ce..81b94f6 100644 --- a/src/main.go +++ b/src/main.go @@ -26,6 +26,7 @@ import ( "sync" "time" + "github.com/coreos/go-semver/semver" _ "github.com/go-sql-driver/mysql" "github.com/pingcap/errors" "github.com/pingcap/tidb/parser" @@ -162,10 +163,44 @@ func setSessionVariable(db *sql.DB) { if _, err := db.Exec("SET @@tidb_enable_pseudo_for_outdated_stats=false"); err != nil { log.Fatalf("Executing \"SET @@tidb_enable_pseudo_for_outdated_stats=false\" err[%v]", err) } - // enable tidb_enable_analyze_snapshot in order to let analyze request with SI isolation level to get accurate response - if _, err := db.Exec("SET @@tidb_enable_analyze_snapshot=1"); err != nil { - log.Fatalf("Executing \"SET @@tidb_enable_analyze_snapshot=1\" err[%v]", err) + rows, err := db.Query("select version from INFORMATION_SCHEMA.CLUSTER_INFO where type = 'tidb' limit 1;") + if err != nil { + log.Fatalf("Executing \"select version from INFORMATION_SCHEMA.CLUSTER_INFO where type = 'tidb' limit 1;\" err[%v]", err) + } + defer rows.Close() + var version string + for rows.Next() { + err := rows.Scan(&version) + if err != nil { + log.Fatalf("Executing \"select version from INFORMATION_SCHEMA.CLUSTER_INFO where type = 'tidb' limit 1;\" err[%v]", err) + } + } + isSupportedVersion, err := checkVersion(version) + if err != nil { + log.Fatalf("Comparing version failed, err[%v]", err) + } + if isSupportedVersion { + log.Infof("setting tidb_enable_analyze_snapshot due to valid tidb version[%s]", version) + // enable tidb_enable_analyze_snapshot in order to let analyze request with SI isolation level to get accurate response + if _, err := db.Exec("SET @@tidb_enable_analyze_snapshot=1"); err != nil { + log.Fatalf("Executing \"SET @@tidb_enable_analyze_snapshot=1\" err[%v]", err) + } + } else { + log.Infof("skip setting tidb_enable_analyze_snapshot due to lower tidb version[%s]", version) + } +} + +func checkVersion(version string) (bool, error) { + minVersion := *semver.New("6.2.0-alpha") + ver, err := semver.NewVersion(version) + if err != nil { + return false, fmt.Errorf("invalid version: %s", version) + } + v := ver.Compare(minVersion) + if v < 0 { + return false, nil } + return true, nil } // isTiDB returns true if the DB is confirmed to be TiDB From 510278c42e793f0624b3a165537592cf62329e8e Mon Sep 17 00:00:00 2001 From: Song Gao Date: Sat, 20 Aug 2022 14:57:45 +0800 Subject: [PATCH 13/19] use tidb_version to get tidb version (#79) --- src/main.go | 57 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/src/main.go b/src/main.go index 81b94f6..3850a6b 100644 --- a/src/main.go +++ b/src/main.go @@ -20,6 +20,7 @@ import ( "fmt" "io/ioutil" "os" + "regexp" "sort" "strconv" "strings" @@ -163,44 +164,60 @@ func setSessionVariable(db *sql.DB) { if _, err := db.Exec("SET @@tidb_enable_pseudo_for_outdated_stats=false"); err != nil { log.Fatalf("Executing \"SET @@tidb_enable_pseudo_for_outdated_stats=false\" err[%v]", err) } - rows, err := db.Query("select version from INFORMATION_SCHEMA.CLUSTER_INFO where type = 'tidb' limit 1;") - if err != nil { - log.Fatalf("Executing \"select version from INFORMATION_SCHEMA.CLUSTER_INFO where type = 'tidb' limit 1;\" err[%v]", err) - } - defer rows.Close() - var version string - for rows.Next() { - err := rows.Scan(&version) - if err != nil { - log.Fatalf("Executing \"select version from INFORMATION_SCHEMA.CLUSTER_INFO where type = 'tidb' limit 1;\" err[%v]", err) - } - } - isSupportedVersion, err := checkVersion(version) + tidbVersion, isSupportedVersion, err := checkVersion(db) if err != nil { log.Fatalf("Comparing version failed, err[%v]", err) } if isSupportedVersion { - log.Infof("setting tidb_enable_analyze_snapshot due to valid tidb version[%s]", version) + log.Infof("setting tidb_enable_analyze_snapshot due to valid tidb version[%s]", tidbVersion) // enable tidb_enable_analyze_snapshot in order to let analyze request with SI isolation level to get accurate response if _, err := db.Exec("SET @@tidb_enable_analyze_snapshot=1"); err != nil { log.Fatalf("Executing \"SET @@tidb_enable_analyze_snapshot=1\" err[%v]", err) } } else { - log.Infof("skip setting tidb_enable_analyze_snapshot due to lower tidb version[%s]", version) + log.Infof("skip setting tidb_enable_analyze_snapshot due to lower tidb version[%s]", tidbVersion) } } -func checkVersion(version string) (bool, error) { +func checkVersion(db *sql.DB) (string, bool, error) { + rs, err := db.Query("select tidb_version();") + if err != nil { + log.Fatalf("Executing \"select tidb_version();\" err[%v]", err) + } + var version string + for rs.Next() { + err := rs.Scan(&version) + if err != nil { + log.Fatalf("Executing \"select tidb_version();\" err[%v]", err) + } + } + defer rs.Close() + prefix := "Release Version: " + rows := strings.Split(version, "\n") + if len(rows[0]) <= len("Release Version: ") { + log.Fatalf("Executing \"select tidb_version();\" get wrong result[%s]", version) + } + tidbVersion := removeVAndHash(rows[0][len(prefix):]) minVersion := *semver.New("6.2.0-alpha") - ver, err := semver.NewVersion(version) + ver, err := semver.NewVersion(tidbVersion) if err != nil { - return false, fmt.Errorf("invalid version: %s", version) + return tidbVersion, false, fmt.Errorf("invalid version: %s", tidbVersion) } v := ver.Compare(minVersion) if v < 0 { - return false, nil + return tidbVersion, false, nil + } + return tidbVersion, true, nil +} + +func removeVAndHash(v string) string { + if v == "" { + return v } - return true, nil + versionHash := regexp.MustCompile("-[0-9]+-g[0-9a-f]{7,}(-dev)?") + v = versionHash.ReplaceAllLiteralString(v, "") + v = strings.TrimSuffix(v, "-dirty") + return strings.TrimPrefix(v, "v") } // isTiDB returns true if the DB is confirmed to be TiDB From a9d9e24ba1f4ef24b4c7b6a7871c4f763516f3c6 Mon Sep 17 00:00:00 2001 From: Song Gao Date: Mon, 22 Aug 2022 11:50:17 +0800 Subject: [PATCH 14/19] use warn during set tidb_enable_analyze_snapshot if error happened (#80) --- src/main.go | 58 ++++------------------------------------------------- 1 file changed, 4 insertions(+), 54 deletions(-) diff --git a/src/main.go b/src/main.go index 3850a6b..799212b 100644 --- a/src/main.go +++ b/src/main.go @@ -20,14 +20,12 @@ import ( "fmt" "io/ioutil" "os" - "regexp" "sort" "strconv" "strings" "sync" "time" - "github.com/coreos/go-semver/semver" _ "github.com/go-sql-driver/mysql" "github.com/pingcap/errors" "github.com/pingcap/tidb/parser" @@ -164,60 +162,12 @@ func setSessionVariable(db *sql.DB) { if _, err := db.Exec("SET @@tidb_enable_pseudo_for_outdated_stats=false"); err != nil { log.Fatalf("Executing \"SET @@tidb_enable_pseudo_for_outdated_stats=false\" err[%v]", err) } - tidbVersion, isSupportedVersion, err := checkVersion(db) - if err != nil { - log.Fatalf("Comparing version failed, err[%v]", err) - } - if isSupportedVersion { - log.Infof("setting tidb_enable_analyze_snapshot due to valid tidb version[%s]", tidbVersion) - // enable tidb_enable_analyze_snapshot in order to let analyze request with SI isolation level to get accurate response - if _, err := db.Exec("SET @@tidb_enable_analyze_snapshot=1"); err != nil { - log.Fatalf("Executing \"SET @@tidb_enable_analyze_snapshot=1\" err[%v]", err) - } + // enable tidb_enable_analyze_snapshot in order to let analyze request with SI isolation level to get accurate response + if _, err := db.Exec("SET @@tidb_enable_analyze_snapshot=1"); err != nil { + log.Warnf("Executing \"SET @@tidb_enable_analyze_snapshot=1 failed\" err[%v]", err) } else { - log.Infof("skip setting tidb_enable_analyze_snapshot due to lower tidb version[%s]", tidbVersion) - } -} - -func checkVersion(db *sql.DB) (string, bool, error) { - rs, err := db.Query("select tidb_version();") - if err != nil { - log.Fatalf("Executing \"select tidb_version();\" err[%v]", err) - } - var version string - for rs.Next() { - err := rs.Scan(&version) - if err != nil { - log.Fatalf("Executing \"select tidb_version();\" err[%v]", err) - } - } - defer rs.Close() - prefix := "Release Version: " - rows := strings.Split(version, "\n") - if len(rows[0]) <= len("Release Version: ") { - log.Fatalf("Executing \"select tidb_version();\" get wrong result[%s]", version) - } - tidbVersion := removeVAndHash(rows[0][len(prefix):]) - minVersion := *semver.New("6.2.0-alpha") - ver, err := semver.NewVersion(tidbVersion) - if err != nil { - return tidbVersion, false, fmt.Errorf("invalid version: %s", tidbVersion) - } - v := ver.Compare(minVersion) - if v < 0 { - return tidbVersion, false, nil - } - return tidbVersion, true, nil -} - -func removeVAndHash(v string) string { - if v == "" { - return v + log.Info("enable tidb_enable_analyze_snapshot") } - versionHash := regexp.MustCompile("-[0-9]+-g[0-9a-f]{7,}(-dev)?") - v = versionHash.ReplaceAllLiteralString(v, "") - v = strings.TrimSuffix(v, "-dirty") - return strings.TrimPrefix(v, "v") } // isTiDB returns true if the DB is confirmed to be TiDB From 106ea42263badbdd4b225ee0241491aa796eb40d Mon Sep 17 00:00:00 2001 From: CbcWestwolf <1004626265@qq.com> Date: Sun, 28 Aug 2022 13:11:53 +0800 Subject: [PATCH 15/19] Try connect only one time if expectedErrs is not nil (#81) --- src/main.go | 15 ++++++++++++--- src/util.go | 8 ++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/main.go b/src/main.go index 799212b..7aa078a 100644 --- a/src/main.go +++ b/src/main.go @@ -180,11 +180,20 @@ func isTiDB(db *sql.DB) bool { } func (t *tester) addConnection(connName, hostName, userName, password, db string) { - mdb, err := OpenDBWithRetry("mysql", userName+":"+password+"@tcp("+hostName+":"+port+")/"+db+"?time_zone=%27Asia%2FShanghai%27&allowAllFiles=true"+params) + var ( + mdb *sql.DB + err error + ) + if t.expectedErrs == nil { + mdb, err = OpenDBWithRetry("mysql", userName+":"+password+"@tcp("+hostName+":"+port+")/"+db+"?time_zone=%27Asia%2FShanghai%27&allowAllFiles=true"+params, retryConnCount) + } else { + mdb, err = OpenDBWithRetry("mysql", userName+":"+password+"@tcp("+hostName+":"+port+")/"+db+"?time_zone=%27Asia%2FShanghai%27&allowAllFiles=true"+params, 1) + } if err != nil { if t.expectedErrs == nil { log.Fatalf("Open db err %v", err) } + t.expectedErrs = nil return } if isTiDB(mdb) { @@ -230,7 +239,7 @@ func (t *tester) disconnect(connName string) { func (t *tester) preProcess() { dbName := "test" - mdb, err := OpenDBWithRetry("mysql", user+":"+passwd+"@tcp("+host+":"+port+")/"+dbName+"?time_zone=%27Asia%2FShanghai%27&allowAllFiles=true"+params) + mdb, err := OpenDBWithRetry("mysql", user+":"+passwd+"@tcp("+host+":"+port+")/"+dbName+"?time_zone=%27Asia%2FShanghai%27&allowAllFiles=true"+params, retryConnCount) t.conn = make(map[string]*Conn) if err != nil { log.Fatalf("Open db err %v", err) @@ -464,7 +473,7 @@ func (t *tester) concurrentExecute(querys []query, wg *sync.WaitGroup, errOccure defer wg.Done() tt := newTester(t.name) dbName := "test" - mdb, err := OpenDBWithRetry("mysql", user+":"+passwd+"@tcp("+host+":"+port+")/"+dbName+"?time_zone=%27Asia%2FShanghai%27&allowAllFiles=true"+params) + mdb, err := OpenDBWithRetry("mysql", user+":"+passwd+"@tcp("+host+":"+port+")/"+dbName+"?time_zone=%27Asia%2FShanghai%27&allowAllFiles=true"+params, retryConnCount) if err != nil { log.Fatalf("Open db err %v", err) } diff --git a/src/util.go b/src/util.go index aa082ec..3be2f46 100644 --- a/src/util.go +++ b/src/util.go @@ -24,14 +24,14 @@ import ( // OpenDBWithRetry opens a database specified by its database driver name and a // driver-specific data source name. And it will do some retries if the connection fails. -func OpenDBWithRetry(driverName, dataSourceName string) (mdb *sql.DB, err error) { +func OpenDBWithRetry(driverName, dataSourceName string, retryCount int) (mdb *sql.DB, err error) { startTime := time.Now() sleepTime := time.Millisecond * 500 // The max retry interval is 60 s. - for i := 0; i < retryConnCount; i++ { + for i := 0; i < retryCount; i++ { mdb, err = sql.Open(driverName, dataSourceName) if err != nil { - log.Warnf("open db failed, retry count %d (remain %d) err %v", i, retryConnCount-i, err) + log.Warnf("open db failed, retry count %d (remain %d) err %v", i, retryCount-i, err) time.Sleep(sleepTime) continue } @@ -39,7 +39,7 @@ func OpenDBWithRetry(driverName, dataSourceName string) (mdb *sql.DB, err error) if err == nil { break } - log.Warnf("ping db failed, retry count %d (remain %d) err %v", i, retryConnCount-i, err) + log.Warnf("ping db failed, retry count %d (remain %d) err %v", i, retryCount-i, err) mdb.Close() time.Sleep(sleepTime) } From a4678646a20af41e9f130dfbd1d3af883b1667a7 Mon Sep 17 00:00:00 2001 From: tangenta Date: Fri, 4 Nov 2022 00:34:38 +0800 Subject: [PATCH 16/19] set clustered index config to 'int_only' (#82) --- src/main.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main.go b/src/main.go index 7aa078a..58cfac2 100644 --- a/src/main.go +++ b/src/main.go @@ -168,6 +168,12 @@ func setSessionVariable(db *sql.DB) { } else { log.Info("enable tidb_enable_analyze_snapshot") } + if _, err := db.Exec("SET @@tidb_enable_clustered_index='int_only'"); err != nil { + log.Fatalf("Executing \"SET @@tidb_enable_clustered_index='int_only'\" err[%v]", err) + } + if _, err := db.Exec("SET @@global.tidb_enable_clustered_index='int_only'"); err != nil { + log.Fatalf("Executing \"SET @@tidb_enable_clustered_index='int_only'\" err[%v]", err) + } } // isTiDB returns true if the DB is confirmed to be TiDB From 98e296f446cbb6576317f8717b9c917bb3c82bd9 Mon Sep 17 00:00:00 2001 From: tangenta Date: Fri, 4 Nov 2022 08:59:01 +0800 Subject: [PATCH 17/19] do not set global variable (#83) --- src/main.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main.go b/src/main.go index 58cfac2..5e4b5d8 100644 --- a/src/main.go +++ b/src/main.go @@ -171,9 +171,6 @@ func setSessionVariable(db *sql.DB) { if _, err := db.Exec("SET @@tidb_enable_clustered_index='int_only'"); err != nil { log.Fatalf("Executing \"SET @@tidb_enable_clustered_index='int_only'\" err[%v]", err) } - if _, err := db.Exec("SET @@global.tidb_enable_clustered_index='int_only'"); err != nil { - log.Fatalf("Executing \"SET @@tidb_enable_clustered_index='int_only'\" err[%v]", err) - } } // isTiDB returns true if the DB is confirmed to be TiDB From 281e39d978d219a642d9f54a107ff64271b8ebb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20Eeden?= Date: Tue, 8 Nov 2022 19:17:27 +0100 Subject: [PATCH 18/19] Support for --remove_file (#47) --- src/main.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main.go b/src/main.go index 5e4b5d8..d971b8a 100644 --- a/src/main.go +++ b/src/main.go @@ -427,6 +427,11 @@ func (t *tester) Run() error { q.Query = q.Query[:len(q.Query)-1] } t.disconnect(q.Query) + case Q_REMOVE_FILE: + err = os.Remove(strings.TrimSpace(q.Query)) + if err != nil { + return errors.Annotate(err, "failed to remove file") + } } } From ef8ec16d215875a20cadd79d74314b9fb9f37b15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20Eeden?= Date: Tue, 8 Nov 2022 20:36:56 +0100 Subject: [PATCH 19/19] Update dependencies (#84) --- go.mod | 5 ++--- go.sum | 25 +++++++++++++++++-------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 0796a71..d5dcbb8 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.12 require ( github.com/benbjohnson/clock v1.3.0 // indirect - github.com/coreos/go-semver v0.3.0 github.com/go-sql-driver/mysql v1.6.0 github.com/pingcap/errors v0.11.5-0.20211009033009-93128226aaa3 github.com/pingcap/log v1.1.0 // indirect @@ -13,7 +12,7 @@ require ( github.com/sirupsen/logrus v1.8.1 go.uber.org/multierr v1.8.0 // indirect go.uber.org/zap v1.21.0 // indirect - golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/sys v0.2.0 // indirect + golang.org/x/text v0.4.0 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect ) diff --git a/go.sum b/go.sum index a6691e2..53db2a0 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc= @@ -42,6 +40,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -62,41 +61,51 @@ go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 h1:kwrAHlwJ0DUBZwQ238v+Uod/3eZ8B2K5rYsUHBQvzmI= -golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=