Skip to content
  • Sponsor
  • Notifications You must be signed in to change notification settings
  • Fork 30
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[no-release-notes] handle doltgres server in the harness for logictest #94

Merged
merged 13 commits into from
Jan 18, 2024
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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
12 changes: 6 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
@@ -6,19 +6,19 @@ 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
github.com/google/go-cmp v0.6.0
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
23 changes: 10 additions & 13 deletions go.sum
Original file line number Diff line number Diff line change
@@ -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=
16 changes: 11 additions & 5 deletions testing/logictest/harness/doltgres_harness.go
Original file line number Diff line number Diff line change
@@ -28,23 +28,25 @@ 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
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
354 changes: 354 additions & 0 deletions testing/logictest/harness/doltgres_server_harness.go
Original file line number Diff line number Diff line change
@@ -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)
}
17 changes: 16 additions & 1 deletion testing/logictest/main.go
Original file line number Diff line number Diff line change
@@ -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=<path to doltgres> run [tests]
if *withServer {
if *doltgres == "" {
log.Fatal("Must supply --doltgres=<path to 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 {