diff --git a/Makefile b/Makefile index 789a895..594846f 100644 --- a/Makefile +++ b/Makefile @@ -5,10 +5,7 @@ GO := go default: build build: - $(GO) build -o vitess-tester ./src/vitess-tester - -debug: - $(GO) build -gcflags="all=-N -l" -o vitess-tester ./src/vitess-tester + $(GO) build -o vitess-tester ./ test: build $(GO) test -cover ./... @@ -20,6 +17,3 @@ tidy: clean: $(GO) clean -i ./... rm -rf vitess-tester - -gen_perror: generate_perror/main.go - $(GO) build -o gen_perror ./generate_perror diff --git a/src/vitess-tester/main.go b/main.go similarity index 87% rename from src/vitess-tester/main.go rename to main.go index 5c581c1..d1a14ff 100644 --- a/src/vitess-tester/main.go +++ b/main.go @@ -27,6 +27,8 @@ import ( "vitess.io/vitess/go/test/endtoend/utils" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vtgate/vindexes" + + vitess_tester "github.com/vitessio/vitess-tester/src/vitess-tester" ) var ( @@ -45,13 +47,6 @@ func init() { flag.BoolVar(&xunit, "xunit", false, "Get output in an xml file instead of errors directory") } -type query struct { - firstWord string - Query string - Line int - tp CmdType -} - func loadAllTests() (tests []string, err error) { // tests must be in t folder or subdir in t folder err = filepath.Walk("./t/", func(path string, info os.FileInfo, err error) error { @@ -72,10 +67,10 @@ func loadAllTests() (tests []string, err error) { return tests, nil } -func executeTests(fileNames []string, s Suite) (failed bool) { +func executeTests(clusterInstance *cluster.LocalProcessCluster, vtParams, mysqlParams mysql.ConnParams, fileNames []string, s vitess_tester.Suite) (failed bool) { for _, name := range fileNames { errReporter := s.NewReporterForFile(name) - vTester := newTester(name, errReporter) + vTester := vitess_tester.NewTester(name, errReporter, clusterInstance, vtParams, mysqlParams, olap, keyspaceName, vschema, vschemaFile) err := vTester.Run() if err != nil { failed = true @@ -88,12 +83,8 @@ func executeTests(fileNames []string, s Suite) (failed bool) { } var ( - clusterInstance *cluster.LocalProcessCluster - keyspaceName = "mysqltest" - cell = "mysqltest" - - vtParams mysql.ConnParams - mysqlParams mysql.ConnParams + keyspaceName = "mysqltest" + cell = "mysqltest" ) type rawKeyspaceVindex struct { @@ -122,7 +113,7 @@ var vschema = vindexes.VSchema{ }, } -func setupCluster(sharded bool) func() { +func setupCluster(sharded bool) (clusterInstance *cluster.LocalProcessCluster, vtParams, mysqlParams mysql.ConnParams, close func()) { clusterInstance = cluster.NewCluster(cell, "localhost") // Start topo server @@ -171,7 +162,7 @@ func setupCluster(sharded bool) func() { } mysqlParams = conn - return func() { + return clusterInstance, vtParams, mysqlParams, func() { clusterInstance.Teardown() closer() } @@ -257,7 +248,7 @@ func main() { log.Infof("running tests: %v", tests) - closer := setupCluster(sharded) + clusterInstance, vtParams, mysqlParams, closer := setupCluster(sharded) defer closer() // remove errors folder if exists @@ -266,13 +257,13 @@ func main() { panic(err.Error()) } - var reporterSuite Suite + var reporterSuite vitess_tester.Suite if xunit { - reporterSuite = newXMLTestSuite() + reporterSuite = vitess_tester.NewXMLTestSuite() } else { - reporterSuite = newFileReporterSuite() + reporterSuite = vitess_tester.NewFileReporterSuite() } - failed := executeTests(tests, reporterSuite) + failed := executeTests(clusterInstance, vtParams, mysqlParams, tests, reporterSuite) outputFile := reporterSuite.Close() if failed { log.Errorf("some tests failed 😭\nsee errors in %v", outputFile) diff --git a/src/vitess-tester/query.go b/src/vitess-tester/query.go index 0d8fe52..e14234c 100644 --- a/src/vitess-tester/query.go +++ b/src/vitess-tester/query.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package main +package vitess_tester import ( "strings" @@ -130,6 +130,13 @@ const ( Q_VEXPLAIN ) +type query struct { + firstWord string + Query string + Line int + tp CmdType +} + // ParseQueries parses an array of string into an array of query object. // Note: a query statement may reside in several lines. func ParseQueries(qs ...query) ([]query, error) { diff --git a/src/vitess-tester/query_test.go b/src/vitess-tester/query_test.go index 7453fec..adeb076 100644 --- a/src/vitess-tester/query_test.go +++ b/src/vitess-tester/query_test.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package main +package vitess_tester import ( "fmt" diff --git a/src/vitess-tester/reporter.go b/src/vitess-tester/reporter.go index 2d929fb..c1af5ff 100644 --- a/src/vitess-tester/reporter.go +++ b/src/vitess-tester/reporter.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package main +package vitess_tester import ( "encoding/json" @@ -24,6 +24,8 @@ import ( "path" "strings" "time" + + "vitess.io/vitess/go/vt/vtgate/vindexes" ) type Suite interface { @@ -35,7 +37,7 @@ type Suite interface { type Reporter interface { AddTestCase(query string, lineNo int) EndTestCase() - AddFailure(err error) + AddFailure(vschema vindexes.VSchema, err error) Report() string Failed() bool } @@ -52,7 +54,7 @@ func (frs *FileReporterSuite) Close() string { return "errors" } -func newFileReporterSuite() *FileReporterSuite { +func NewFileReporterSuite() *FileReporterSuite { return &FileReporterSuite{} } @@ -115,7 +117,7 @@ func (e *FileReporter) EndTestCase() { } } -func (e *FileReporter) AddFailure(err error) { +func (e *FileReporter) AddFailure(vschema vindexes.VSchema, err error) { e.failureCount++ e.currentQueryFailed = true if e.currentQuery == "" { @@ -130,7 +132,7 @@ func (e *FileReporter) AddFailure(err error) { panic("failed to write error file\n" + err.Error()) } - e.createVSchemaDump() + e.createVSchemaDump(vschema) } func (e *FileReporter) createErrorFileFor() *os.File { @@ -152,7 +154,7 @@ func (e *FileReporter) createErrorFileFor() *os.File { return file } -func (e *FileReporter) createVSchemaDump() { +func (e *FileReporter) createVSchemaDump(vschema vindexes.VSchema) { errorDir := e.errorDir() err := os.MkdirAll(errorDir, PERM) if err != nil { diff --git a/src/vitess-tester/tester.go b/src/vitess-tester/tester.go index 284e88f..640e8f2 100644 --- a/src/vitess-tester/tester.go +++ b/src/vitess-tester/tester.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package main +package vitess_tester import ( "bytes" @@ -28,6 +28,8 @@ import ( "github.com/pingcap/errors" log "github.com/sirupsen/logrus" + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/test/endtoend/cluster" "vitess.io/vitess/go/test/endtoend/utils" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vtgate/vindexes" @@ -36,12 +38,18 @@ import ( type tester struct { name string - curr utils.MySQLCompare + clusterInstance *cluster.LocalProcessCluster + vtParams, mysqlParams mysql.ConnParams + curr utils.MySQLCompare - skipBinary string - skipVersion int - skipNext bool - vexplain string + skipBinary string + skipVersion int + skipNext bool + olap bool + keyspaceName string + vschema vindexes.VSchema + vschemaFile string + vexplain string // check expected error, use --error before the statement // we only care if an error is returned, not the exact error message. @@ -50,21 +58,36 @@ type tester struct { reporter Reporter } -func newTester(name string, reporter Reporter) *tester { - t := new(tester) - t.name = name - t.reporter = reporter - +func NewTester(name string, reporter Reporter, + clusterInstance *cluster.LocalProcessCluster, + vtParams, + mysqlParams mysql.ConnParams, + olap bool, + keyspaceName string, + vschema vindexes.VSchema, + vschemaFile string, +) *tester { + t := &tester{ + name: name, + reporter: reporter, + vtParams: vtParams, + mysqlParams: mysqlParams, + clusterInstance: clusterInstance, + keyspaceName: keyspaceName, + vschema: vschema, + vschemaFile: vschemaFile, + olap: olap, + } return t } func (t *tester) preProcess() { - mcmp, err := utils.NewMySQLCompare(t, vtParams, mysqlParams) + mcmp, err := utils.NewMySQLCompare(t, t.vtParams, t.mysqlParams) if err != nil { panic(err.Error()) } t.curr = mcmp - if olap { + if t.olap { _, err := t.curr.VtConn.ExecuteFetch("set workload = 'olap'", 0, false) if err != nil { panic(err) @@ -94,7 +117,7 @@ func (t *tester) Run() error { defer t.postProcess() queries, err := t.loadQueries() if err != nil { - t.reporter.AddFailure(err) + t.reporter.AddFailure(t.vschema, err) return err } @@ -116,18 +139,18 @@ func (t *tester) Run() error { case Q_SKIP: t.skipNext = true case Q_BEGIN_CONCURRENT, Q_END_CONCURRENT, Q_CONNECT, Q_CONNECTION, Q_DISCONNECT, Q_LET, Q_REPLACE_COLUMN: - t.reporter.AddFailure(fmt.Errorf("%s not supported", String(q.tp))) + t.reporter.AddFailure(t.vschema, fmt.Errorf("%s not supported", String(q.tp))) case Q_SKIP_IF_BELOW_VERSION: strs := strings.Split(q.Query, " ") if len(strs) != 3 { - t.reporter.AddFailure(fmt.Errorf("incorrect syntax for Q_SKIP_IF_BELOW_VERSION in: %v", q.Query)) + t.reporter.AddFailure(t.vschema, fmt.Errorf("incorrect syntax for Q_SKIP_IF_BELOW_VERSION in: %v", q.Query)) continue } t.skipBinary = strs[1] var err error t.skipVersion, err = strconv.Atoi(strs[2]) if err != nil { - t.reporter.AddFailure(err) + t.reporter.AddFailure(t.vschema, err) continue } case Q_ERROR: @@ -135,7 +158,7 @@ func (t *tester) Run() error { case Q_VEXPLAIN: strs := strings.Split(q.Query, " ") if len(strs) != 2 { - t.reporter.AddFailure(fmt.Errorf("incorrect syntax for Q_VEXPLAIN in: %v", q.Query)) + t.reporter.AddFailure(t.vschema, fmt.Errorf("incorrect syntax for Q_VEXPLAIN in: %v", q.Query)) continue } @@ -156,15 +179,15 @@ func (t *tester) Run() error { result, err := t.curr.VtConn.ExecuteFetch("vexplain "+t.vexplain+" "+q.Query, -1, false) t.vexplain = "" if err != nil { - t.reporter.AddFailure(err) + t.reporter.AddFailure(t.vschema, err) continue } - t.reporter.AddFailure(fmt.Errorf("VExplain Output:\n %s\n", result.Rows[0][0].ToString())) + t.reporter.AddFailure(t.vschema, fmt.Errorf("VExplain Output:\n %s\n", result.Rows[0][0].ToString())) } t.reporter.AddTestCase(q.Query, q.Line) if err = t.execute(q); err != nil && !t.expectedErrs { - t.reporter.AddFailure(err) + t.reporter.AddFailure(t.vschema, err) } t.reporter.EndTestCase() // clear expected errors and current query after we execute any query @@ -175,7 +198,7 @@ func (t *tester) Run() error { return errors.Annotate(err, "failed to remove file") } default: - t.reporter.AddFailure(fmt.Errorf("%s not supported", String(q.tp))) + t.reporter.AddFailure(t.vschema, fmt.Errorf("%s not supported", String(q.tp))) } } fmt.Printf("%s\n", t.reporter.Report()) @@ -282,7 +305,7 @@ func (t *tester) executeStmt(query string) error { log.Debugf("executeStmt: %s", query) create, isCreateStatement := ast.(*sqlparser.CreateTable) - autoVschema := isCreateStatement && !t.expectedErrs && vschemaFile == "" + autoVschema := isCreateStatement && !t.expectedErrs && t.vschemaFile == "" if autoVschema { t.handleCreateTable(create) } @@ -299,7 +322,7 @@ func (t *tester) executeStmt(query string) error { } if autoVschema { - err = utils.WaitForAuthoritative(t, keyspaceName, create.Table.Name.String(), clusterInstance.VtgateProcess.ReadVSchema) + err = utils.WaitForAuthoritative(t, t.keyspaceName, create.Table.Name.String(), t.clusterInstance.VtgateProcess.ReadVSchema) if err != nil { panic(err) } @@ -343,7 +366,7 @@ func (t *tester) handleCreateTable(create *sqlparser.CreateTable) { Type: "xxhash", } - ks := vschema.Keyspaces[keyspaceName] + ks := t.vschema.Keyspaces[t.keyspaceName] tableName := create.Table.Name ks.Tables[tableName.String()] = &vindexes.Table{ Name: tableName, @@ -356,7 +379,7 @@ func (t *tester) handleCreateTable(create *sqlparser.CreateTable) { panic(err) } - err = clusterInstance.VtctldClientProcess.ApplyVSchema(keyspaceName, string(ksJson)) + err = t.clusterInstance.VtctldClientProcess.ApplyVSchema(t.keyspaceName, string(ksJson)) if err != nil { panic(err) } @@ -368,7 +391,7 @@ func (t *tester) testFileName() string { } func (t *tester) Errorf(format string, args ...interface{}) { - t.reporter.AddFailure(errors.Errorf(format, args...)) + t.reporter.AddFailure(t.vschema, errors.Errorf(format, args...)) } func (t *tester) FailNow() { diff --git a/src/vitess-tester/type.go b/src/vitess-tester/type.go index 83c80fb..1d463d3 100644 --- a/src/vitess-tester/type.go +++ b/src/vitess-tester/type.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package main +package vitess_tester import ( "strings" diff --git a/src/vitess-tester/xunit.go b/src/vitess-tester/xunit.go index 1dfe9eb..d623330 100644 --- a/src/vitess-tester/xunit.go +++ b/src/vitess-tester/xunit.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package main +package vitess_tester import ( "fmt" @@ -22,6 +22,7 @@ import ( "time" "github.com/jstemmer/go-junit-report/v2/junit" + "vitess.io/vitess/go/vt/vtgate/vindexes" ) type XMLTestSuite struct { @@ -33,7 +34,7 @@ type XMLTestSuite struct { var _ Suite = (*XMLTestSuite)(nil) -func newXMLTestSuite() *XMLTestSuite { +func NewXMLTestSuite() *XMLTestSuite { return &XMLTestSuite{} } @@ -77,10 +78,10 @@ func (xml *XMLTestSuite) EndTestCase() { xml.currTestCase = nil } -func (xml *XMLTestSuite) AddFailure(err error) { +func (xml *XMLTestSuite) AddFailure(vschema vindexes.VSchema, err error) { if xml.currTestCase == nil { xml.AddTestCase("SETUP", 0) - xml.AddFailure(err) + xml.AddFailure(vschema, err) xml.EndTestCase() return } @@ -97,7 +98,7 @@ func (xml *XMLTestSuite) AddFailure(err error) { func (xml *XMLTestSuite) Report() string { return fmt.Sprintf( - "%s: ok! Ran %d queries, %d successfully and %d failures take time %v s\n", + "%s: ok! Ran %d queries, %d successfully and %d failures take time %v\n", xml.currTestSuite.Name, xml.currTestSuite.Tests, xml.currTestSuite.Tests-xml.currTestSuite.Failures,