diff --git a/.gitignore b/.gitignore index 2322e1f91c..69d500a0c6 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ SysbenchDockerfile.dockerignore sysbench-runner-tests-entrypoint.sh config.json integration-tests/bats/batsee_results + +# ignore log files created from logic test +testing/logictest/*.log diff --git a/go.mod b/go.mod index abc8fbe639..a868740a87 100644 --- a/go.mod +++ b/go.mod @@ -6,11 +6,11 @@ require ( github.com/PuerkitoBio/goquery v1.8.1 github.com/cockroachdb/apd/v2 v2.0.3-0.20200518165714-d020e156310a github.com/cockroachdb/errors v1.7.5 - github.com/dolthub/dolt/go v0.40.5-0.20240110011351-84b9180295cc + github.com/dolthub/dolt/go v0.40.5-0.20240118193700-2398a547fccc github.com/dolthub/dolt/go/gen/proto/dolt/services/eventsapi v0.0.0-20231213233028-64c353bf920f - github.com/dolthub/go-mysql-server v0.17.1-0.20240110234302-66c569a3137e - github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 - github.com/dolthub/vitess v0.0.0-20240110233415-e46007d964c0 + github.com/dolthub/go-mysql-server v0.17.1-0.20240117234409-91a2a9d4b1a1 + github.com/dolthub/sqllogictest/go v0.0.0-20240118211725-a52e3f5697e3 + github.com/dolthub/vitess v0.0.0-20240117231546-55b8c7b39462 github.com/fatih/color v1.13.0 github.com/gogo/protobuf v1.3.2 github.com/golang/geo v0.0.0-20200730024412-e86565bf3f35 @@ -18,7 +18,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/jackc/pgx/v4 v4.18.1 github.com/jackc/pgx/v5 v5.4.3 - github.com/lib/pq v1.10.2 + github.com/lib/pq v1.10.9 github.com/madflojo/testcerts v1.1.1 github.com/pierrre/geohash v1.0.0 github.com/sergi/go-diff v1.1.0 @@ -29,6 +29,7 @@ require ( github.com/twpayne/go-geom v1.3.6 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 golang.org/x/net v0.17.0 + golang.org/x/sync v0.3.0 golang.org/x/sys v0.15.0 golang.org/x/text v0.14.0 ) @@ -138,7 +139,6 @@ require ( golang.org/x/crypto v0.17.0 // indirect golang.org/x/mod v0.12.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sync v0.3.0 // indirect golang.org/x/term v0.15.0 // indirect golang.org/x/time v0.1.0 // indirect golang.org/x/tools v0.13.0 // indirect diff --git a/go.sum b/go.sum index 5636b00d88..503e7512e8 100644 --- a/go.sum +++ b/go.sum @@ -214,8 +214,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dolthub/dolt/go v0.40.5-0.20240110011351-84b9180295cc h1:7C97S8tm3cKL4tZIKaudt4BTBOBgwdZ3ceSExwb+bNo= -github.com/dolthub/dolt/go v0.40.5-0.20240110011351-84b9180295cc/go.mod h1:+oni3DE3qkT79htI/fVogLu00bRTfdu15fL4A3KPr24= +github.com/dolthub/dolt/go v0.40.5-0.20240118193700-2398a547fccc h1:sFL+cYw5UORwM0CZ31rJ+mSSqheL6GN9ICOVfj0tzvs= +github.com/dolthub/dolt/go v0.40.5-0.20240118193700-2398a547fccc/go.mod h1:UeVcSMEmqQFKmKGJz7uH5whri2k/bg005/gUTgZU+VQ= github.com/dolthub/dolt/go/gen/proto/dolt/services/eventsapi v0.0.0-20231213233028-64c353bf920f h1:f250FTgZ/OaCql9G6WJt46l9VOIBF1mI81hW9cnmBNM= github.com/dolthub/dolt/go/gen/proto/dolt/services/eventsapi v0.0.0-20231213233028-64c353bf920f/go.mod h1:gHeHIDGU7em40EhFTliq62pExFcc1hxDTIZ9g5UqXYM= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 h1:u3PMzfF8RkKd3lB9pZ2bfn0qEG+1Gms9599cr0REMww= @@ -224,24 +224,20 @@ github.com/dolthub/fslock v0.0.3 h1:iLMpUIvJKMKm92+N1fmHVdxJP5NdyDK5bK7z7Ba2s2U= github.com/dolthub/fslock v0.0.3/go.mod h1:QWql+P17oAAMLnL4HGB5tiovtDuAjdDTPbuqx7bYfa0= github.com/dolthub/go-icu-regex v0.0.0-20230524105445-af7e7991c97e h1:kPsT4a47cw1+y/N5SSCkma7FhAPw7KeGmD6c9PBZW9Y= github.com/dolthub/go-icu-regex v0.0.0-20230524105445-af7e7991c97e/go.mod h1:KPUcpx070QOfJK1gNe0zx4pA5sicIK1GMikIGLKC168= -github.com/dolthub/go-mysql-server v0.17.1-0.20240110020052-1eabd6054d96 h1:FDMByaljXrMExow4qE3qwQoyRbXku6GBy6jnqPjx4zg= -github.com/dolthub/go-mysql-server v0.17.1-0.20240110020052-1eabd6054d96/go.mod h1:z98pba7qbSvXiceU3NlUbJaYwITxc1Am06YjK6hexXA= -github.com/dolthub/go-mysql-server v0.17.1-0.20240110234302-66c569a3137e h1:FwStPrVtMcFTqaVp8Pk8KH1iCVTyQ58GzlNMO6ak418= -github.com/dolthub/go-mysql-server v0.17.1-0.20240110234302-66c569a3137e/go.mod h1:vANS+BQiobOQ3sfB1Qxm5zqOrsXOaK6S3EE1yb4vJuc= +github.com/dolthub/go-mysql-server v0.17.1-0.20240117234409-91a2a9d4b1a1 h1:CPdkEWpNyz6H1380wwR+pkxXpBQF7vRTjZ7fb/UCqWs= +github.com/dolthub/go-mysql-server v0.17.1-0.20240117234409-91a2a9d4b1a1/go.mod h1:hS8Snuzg+nyTDjv4NI9jiXQ2lJJOd3O0ylhVPQlHySw= github.com/dolthub/ishell v0.0.0-20221214210346-d7db0b066488 h1:0HHu0GWJH0N6a6keStrHhUAK5/o9LVfkh44pvsV4514= github.com/dolthub/ishell v0.0.0-20221214210346-d7db0b066488/go.mod h1:ehexgi1mPxRTk0Mok/pADALuHbvATulTh6gzr7NzZto= github.com/dolthub/jsonpath v0.0.2-0.20230525180605-8dc13778fd72 h1:NfWmngMi1CYUWU4Ix8wM+USEhjc+mhPlT9JUR/anvbQ= github.com/dolthub/jsonpath v0.0.2-0.20230525180605-8dc13778fd72/go.mod h1:ZWUdY4iszqRQ8OcoXClkxiAVAoWoK3cq0Hvv4ddGRuM= github.com/dolthub/maphash v0.0.0-20221220182448-74e1e1ea1577 h1:SegEguMxToBn045KRHLIUlF2/jR7Y2qD6fF+3tdOfvI= github.com/dolthub/maphash v0.0.0-20221220182448-74e1e1ea1577/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4= -github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 h1:7/v8q9XGFa6q5Ap4Z/OhNkAMBaK5YeuEzwJt+NZdhiE= -github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81/go.mod h1:siLfyv2c92W1eN/R4QqG/+RjjX5W2+gCTRjZxBjI3TY= +github.com/dolthub/sqllogictest/go v0.0.0-20240118211725-a52e3f5697e3 h1:+eDpuEJ9t8aag943P27VS5PFNhp5l+6NIJ/Rc3b164o= +github.com/dolthub/sqllogictest/go v0.0.0-20240118211725-a52e3f5697e3/go.mod h1:e/FIZVvT2IR53HBCAo41NjqgtEnjMJGKca3Y/dAmZaA= github.com/dolthub/swiss v0.1.0 h1:EaGQct3AqeP/MjASHLiH6i4TAmgbG/c4rA6a1bzCOPc= github.com/dolthub/swiss v0.1.0/go.mod h1:BeucyB08Vb1G9tumVN3Vp/pyY4AMUnr9p7Rz7wJ7kAQ= -github.com/dolthub/vitess v0.0.0-20240110003421-4030c3dac015 h1:n45HAYH+kmlvZ+lZPKtJoserQJNwgQkyVWZAL7kJpn0= -github.com/dolthub/vitess v0.0.0-20240110003421-4030c3dac015/go.mod h1:IwjNXSQPymrja5pVqmfnYdcy7Uv7eNJNBPK/MEh9OOw= -github.com/dolthub/vitess v0.0.0-20240110233415-e46007d964c0 h1:P8wb4dR5krirPa0swEJbEObc/I7GaAM/01nOnuQrl0c= -github.com/dolthub/vitess v0.0.0-20240110233415-e46007d964c0/go.mod h1:IwjNXSQPymrja5pVqmfnYdcy7Uv7eNJNBPK/MEh9OOw= +github.com/dolthub/vitess v0.0.0-20240117231546-55b8c7b39462 h1:So1KO202cb047yWg5X27xRso6tkSYmU0Yu96JIVsaEU= +github.com/dolthub/vitess v0.0.0-20240117231546-55b8c7b39462/go.mod h1:IwjNXSQPymrja5pVqmfnYdcy7Uv7eNJNBPK/MEh9OOw= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -611,8 +607,9 @@ github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lyft/protoc-gen-star v0.5.2/go.mod h1:9toiA3cC7z5uVbODF7kEQ91Xn7XNFkVUl+SrEe+ZORU= diff --git a/testing/logictest/harness/doltgres_harness.go b/testing/logictest/harness/doltgres_harness.go index fb06020bfa..559b3858c1 100755 --- a/testing/logictest/harness/doltgres_harness.go +++ b/testing/logictest/harness/doltgres_harness.go @@ -28,8 +28,9 @@ var _ logictest.Harness = &PostgresqlServerHarness{} // sqllogictest harness for postgres databases. type PostgresqlServerHarness struct { - dsn string - db *sql.DB + dsn string + db *sql.DB + timeout int64 } // compile check for interface compliance @@ -37,14 +38,15 @@ var _ logictest.Harness = &PostgresqlServerHarness{} // NewPostgresqlHarness returns a new Postgres test harness for the data source name given. Panics if it cannot open a // connection using the DSN. -func NewPostgresqlHarness(dsn string) *PostgresqlServerHarness { +func NewPostgresqlHarness(dsn string, t int64) *PostgresqlServerHarness { db, err := sql.Open("pgx", dsn) if err != nil { panic(err) } return &PostgresqlServerHarness{ - dsn: dsn, - db: db, + dsn: dsn, + db: db, + timeout: t, } } @@ -100,6 +102,10 @@ func (h *PostgresqlServerHarness) ExecuteQuery(statement string) (schema string, return schema, results, nil } +func (h *PostgresqlServerHarness) GetTimeout() int64 { + return h.timeout +} + func (h *PostgresqlServerHarness) dropAllTables() error { var rows *sql.Rows var err error diff --git a/testing/logictest/harness/doltgres_server_harness.go b/testing/logictest/harness/doltgres_server_harness.go new file mode 100644 index 0000000000..b9b55cabee --- /dev/null +++ b/testing/logictest/harness/doltgres_server_harness.go @@ -0,0 +1,354 @@ +// Copyright 2024 Dolthub, 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 harness + +import ( + "context" + "database/sql" + "fmt" + "log" + "os" + "os/exec" + "os/signal" + "path/filepath" + "strings" + "sync" + "syscall" + "time" + + "golang.org/x/sync/errgroup" + + "github.com/dolthub/sqllogictest/go/logictest" + _ "github.com/jackc/pgx/v4/stdlib" +) + +const ( + dsn = "postgresql://postgres:password@localhost:5432/sqllogictest?sslmode=disable" + doltgresDBDir = "doltgresDatabases" + serverLogFile = "server.log" + harnessLogFile = "harness.log" +) + +var _ logictest.Harness = &DoltgresHarness{} + +// DoltgresHarness is sqllogictest harness for doltgres databases. +type DoltgresHarness struct { + db *sql.DB + doltgresExec string + server *DoltgresServer + serverDir string + timeout int64 // in seconds +} + +// NewDoltgresHarness returns a new Doltgres test harness for the data source name given. +// It starts doltgres server and handles every connection to it. +func NewDoltgresHarness(doltgresExec string, t int64) *DoltgresHarness { + serverDir := prepareSqlLogicTestDBAndGetServerDir(context.Background(), doltgresExec) + logFile, err := os.OpenFile(harnessLogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + log.Fatal(err) + } + log.SetOutput(logFile) + logMsg("creating a new DoltgresHarness") + + return &DoltgresHarness{ + doltgresExec: doltgresExec, + serverDir: serverDir, + timeout: t, + } +} + +func (h *DoltgresHarness) EngineStr() string { + return "postgresql" +} + +func (h *DoltgresHarness) Init() error { + h.startNewDoltgresServer(context.Background(), logictest.GetCurrentFileName()) + db, err := sql.Open("pgx", dsn) + if err != nil { + logErr(err, "opening connection to pgx") + return err + } + h.db = db + + if err := h.dropAllTables(); err != nil { + return err + } + + return h.dropAllViews() +} + +func (s *DoltgresHarness) Close() error { + s.server.Close() + s.server = nil + return os.RemoveAll(s.serverDir) +} + +func (h *DoltgresHarness) ExecuteStatement(statement string) error { + _, err := h.db.Exec(statement) + return err +} + +func (h *DoltgresHarness) ExecuteQuery(statement string) (schema string, results []string, err error) { + rows, err := h.db.Query(statement) + if rows != nil { + defer rows.Close() + } + + if err != nil { + return "", nil, err + } + + schema, columns, err := columns(rows) + if err != nil { + return "", nil, err + } + + for rows.Next() { + err := rows.Scan(columns...) + if err != nil { + return "", nil, err + } + + for _, col := range columns { + results = append(results, stringVal(col)) + } + } + + if rows.Err() != nil { + return "", nil, rows.Err() + } + + return schema, results, nil +} + +func (h *DoltgresHarness) GetTimeout() int64 { + return h.timeout +} + +func (h *DoltgresHarness) dropAllTables() error { + var rows *sql.Rows + var err error + rows, err = h.db.QueryContext(context.Background(), "SELECT table_name FROM information_schema.tables WHERE table_schema = 'sqllogictest' AND table_type = 'BASE TABLE';") + if rows != nil { + defer rows.Close() + } + if err != nil { + return err + } + + _, columns, err := columns(rows) + if err != nil { + return err + } + + var tableNames []string + for rows.Next() { + err := rows.Scan(columns...) + if err != nil { + return err + } + + tableName := columns[0].(*sql.NullString) + tableNames = append(tableNames, tableName.String) + } + + if len(tableNames) > 0 { + dropTables := "drop table if exists " + strings.Join(tableNames, ",") + _, err = h.db.Exec(dropTables) + if err != nil { + return err + } + } + + return nil +} + +func (h *DoltgresHarness) dropAllViews() error { + rows, err := h.db.QueryContext(context.Background(), "select table_name from INFORMATION_SCHEMA.views") + if rows != nil { + defer rows.Close() + } + if err != nil { + return err + } + + _, columns, err := columns(rows) + if err != nil { + return err + } + + var viewNames []string + for rows.Next() { + err := rows.Scan(columns...) + if err != nil { + return err + } + + viewName := columns[0].(*sql.NullString) + viewNames = append(viewNames, viewName.String) + } + + if len(viewNames) > 0 { + dropView := "drop view if exists " + strings.Join(viewNames, ",") + _, err = h.db.Exec(dropView) + if err != nil { + return err + } + } + + return nil +} + +// startNewDoltgresServer stops the existing server if exists. +// It starts a new server and update the |server| of the harness. +func (h *DoltgresHarness) startNewDoltgresServer(ctx context.Context, newTestFile string) { + if h.server != nil { + h.server.Stop() + h.server = nil + } + + withKeyCtx, cancel := context.WithCancel(ctx) + gServer, serverCtx := errgroup.WithContext(withKeyCtx) + + server := exec.CommandContext(serverCtx, h.doltgresExec, "--data-dir=.") + server.Dir = h.serverDir + + // open log file for server output + l, err := os.OpenFile(serverLogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + logErr(err, fmt.Sprintf("opening %s file", serverLogFile)) + } + server.Stdout = l + server.Stderr = l + + // handle user interrupt + quit := make(chan os.Signal, 1) + signal.Notify(quit, os.Interrupt, syscall.SIGTERM) + var wg sync.WaitGroup + wg.Add(1) + go func() { + <-quit + defer wg.Done() + signal.Stop(quit) + cancel() + }() + + doltgresServer := &DoltgresServer{ + dir: h.serverDir, + quit: quit, + wg: &wg, + gServer: gServer, + server: server, + testFile: newTestFile, + } + + h.server = doltgresServer + h.server.Start() +} + +func prepareSqlLogicTestDBAndGetServerDir(ctx context.Context, doltgresExec string) string { + cwd, err := os.Getwd() + if err != nil { + logErr(err, "getting cwd") + } + + serverDir := filepath.Join(cwd, doltgresDBDir) + // remove this dir to make sure it doesn't exist from previous run + err = os.RemoveAll(serverDir) + if err != nil { + logErr(err, "running `RemoveAll`") + } + + // this creates db named 'sqllogictest' + logicTestDbDir := filepath.Join(serverDir, "sqllogictest") + err = os.MkdirAll(logicTestDbDir, os.ModePerm) + if err != nil { + logErr(err, "running `MkdirAll`") + } + + testInit := exec.CommandContext(ctx, doltgresExec, "init") + testInit.Dir = logicTestDbDir + err = testInit.Run() + if err != nil { + logErr(err, "running `doltgres init`") + } + + return serverDir +} + +type DoltgresServer struct { + dir string + quit chan os.Signal + wg *sync.WaitGroup + gServer *errgroup.Group + server *exec.Cmd + testFile string +} + +func (s *DoltgresServer) Start() { + logMsg(fmt.Sprintf("starting doltgres server for: %s", s.testFile)) + var err error + // launch the dolt server + s.gServer.Go(func() error { + err = s.server.Run() + return err + }) + + // sleep to allow the server to start + time.Sleep(3 * time.Second) + if err != nil { + logErr(err, "from server.Start()") + } +} + +func (s *DoltgresServer) Stop() { + select { + case <-s.quit: + // closed + return + default: + } + + // send signal to dolt server + s.quit <- syscall.SIGTERM + //defer s.isRunning.Store(false) + err := s.gServer.Wait() + if err != nil { + // we expect a kill error + // we only exit in error + // if this is not the error + if err.Error() == "signal: killed" { + logMsg("doltgres server is stopped successfully from SIGTERM") + } else { + logErr(err, "from server.Stop()") + } + } + + close(s.quit) + s.wg.Wait() +} + +func (s *DoltgresServer) Close() { + s.Stop() +} + +func logErr(err error, cause string) { + log.Printf("ERROR: %s received from %s", err.Error(), cause) +} + +func logMsg(msg string) { + log.Println(msg) +} diff --git a/testing/logictest/main.go b/testing/logictest/main.go index 0d20c1a9ab..73341c633d 100755 --- a/testing/logictest/main.go +++ b/testing/logictest/main.go @@ -20,6 +20,7 @@ import ( "encoding/json" "flag" "fmt" + "log" "os" "github.com/dolthub/sqllogictest/go/logictest" @@ -28,6 +29,9 @@ import ( ) var resultFormat = flag.String("r", "json", "format of parsed results") +var withServer = flag.Bool("server", false, "format of parsed results") +var doltgres = flag.String("doltgres", "", "local doltgres binary") +var timeout = flag.Int64("timeout", 0, "set a timeout (in seconds) for each test query") // Runs all sqllogictest test files (or directories containing them) given as arguments. // Usage: $command (run|parse) [version] [file1.test dir1/ dir2/] @@ -42,7 +46,18 @@ func main() { } if args[0] == "run" { - h := harness.NewPostgresqlHarness("postgresql://postgres:password@localhost:5432/sqllogictest?sslmode=disable") + var h logictest.Harness + // to run with server: $command --server=true --doltgres= run [tests] + if *withServer { + if *doltgres == "" { + log.Fatal("Must supply --doltgres= with --server=true") + } + dh := harness.NewDoltgresHarness(*doltgres, *timeout) + defer dh.Close() + h = dh + } else { + h = harness.NewPostgresqlHarness("postgresql://postgres:password@localhost:5432/sqllogictest?sslmode=disable", *timeout) + } logictest.RunTestFiles(h, args[1:]...) } else if args[0] == "parse" { if len(args) < 3 {