Skip to content

Commit

Permalink
Golang localtests
Browse files Browse the repository at this point in the history
  • Loading branch information
timvaillancourt committed Nov 17, 2022
1 parent 9b3fa79 commit d9ce3ea
Show file tree
Hide file tree
Showing 18 changed files with 1,072 additions and 19 deletions.
21 changes: 21 additions & 0 deletions Dockerfile.ripple
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
FROM ubuntu:bionic AS build

RUN apt-get update && apt-get install -y gnupg2 wget curl lsb-release git pkg-config \
zip g++ zlib1g-dev unzip python libssl-dev default-jdk-headless libmariadbclient-dev

RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | tee /etc/apt/sources.list.d/bazel.list
RUN curl https://bazel.build/bazel-release.pub.gpg | apt-key add -
RUN apt-get update && apt-get install -y bazel

RUN git clone https://github.com/google/mysql-ripple.git && \
cd mysql-ripple && \
bazel build :all && \
bazel test :all

FROM ubuntu:bionic

RUN apt-get update && apt-get install -y libssl-dev

COPY --from=build /mysql-ripple/bazel-bin/rippled /usr/local/bin/rippled

ENTRYPOINT ["rippled"]
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ require (
github.com/go-ini/ini v1.62.0
github.com/go-mysql-org/go-mysql v1.3.0
github.com/go-sql-driver/mysql v1.6.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/openark/golib v0.0.0-20210531070646-355f37940af8
github.com/satori/go.uuid v1.2.0
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467
golang.org/x/text v0.3.6
)

Expand All @@ -21,7 +22,6 @@ require (
github.com/smartystreets/goconvey v1.6.4 // indirect
go.uber.org/atomic v1.7.0 // indirect
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
)
8 changes: 2 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/jmoiron/sqlx v1.3.3/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
Expand Down Expand Up @@ -81,8 +83,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
Expand All @@ -96,14 +96,10 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM=
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
Expand Down
87 changes: 87 additions & 0 deletions go/cmd/gh-ost-localtests/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package main

import (
"database/sql"
"flag"
"fmt"
"log"
"os"
"path/filepath"

_ "github.com/go-sql-driver/mysql"

"github.com/github/gh-ost/go/localtests"
)

var AppVersion string

func main() {
pwd, err := os.Getwd()
if err != nil {
panic(err)
}

var printVersion, testNoop bool
var localtestsDir, testName string
var cnf localtests.Config

flag.StringVar(&cnf.Host, "host", localtests.DefaultHost, "mysql host")
flag.Int64Var(&cnf.Port, "port", localtests.DefaultPort, "mysql port")
flag.StringVar(&cnf.Username, "username", localtests.DefaultUsername, "mysql username")
flag.StringVar(&cnf.Password, "password", localtests.DefaultPassword, "mysql password")
flag.StringVar(&localtestsDir, "tests-dir", filepath.Join(pwd, "localtests"), "path to localtests directory")
flag.StringVar(&testName, "test", "", "run a single test by name (default: run all tests)")
flag.BoolVar(&testNoop, "test-noop", false, "run a single noop migration, eg: --alter='ENGINE=InnoDB'")
flag.StringVar(&cnf.GhostBinary, "binary", "gh-ost", "path to gh-ost binary")
flag.StringVar(&cnf.MysqlBinary, "mysql-binary", "mysql", "path to mysql binary")
flag.BoolVar(&printVersion, "version", false, "print version and exit")
flag.Parse()

if printVersion {
fmt.Println(AppVersion)
os.Exit(0)
}

db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/?interpolateParams=true",
cnf.Username,
cnf.Password,
cnf.Host,
cnf.Port,
))
if err != nil {
log.Fatal(err)
}
defer db.Close()

if err = localtests.WaitForMySQLAvailable(db); err != nil {
log.Fatalf("Failed to setup database client: %+v", err)
}

var tests []localtests.Test
if testNoop {
tests = []localtests.Test{
{
Name: "noop",
ExtraArgs: []string{
`--alter='ENGINE=InnoDB'`,
},
},
}
} else {
tests, err = localtests.ReadTests(localtestsDir)
if err != nil {
log.Fatalf("Failed to read tests: %+v", err)
}
}

for _, test := range tests {
if testName != "" && test.Name != testName {
continue
}

log.Printf("Found test %q at %s/%s", test.Name, localtestsDir, test.Name)
if err = localtests.RunTest(db, cnf, test); err != nil {
log.Fatalf("Failed to run test %s: %+v", test.Name, err)
}
}
}
202 changes: 202 additions & 0 deletions go/localtests/localtests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
package localtests

import (
"database/sql"
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"time"

"github.com/google/shlex"
)

const (
PrimaryHost = "primary"
DefaultHost = "replica"
DefaultPort int64 = 3306
DefaultUsername = "gh-ost"
DefaultPassword = "gh-ost"
testDatabase = "test"
testTable = "gh_ost_test"
testSocketFile = "/tmp/gh-ost.test.sock"
throttleFlagFile = "/tmp/gh-ost-test.ghost.throttle.flag"
throttleQuery = "select timestampdiff(second, min(last_update), now()) < 5 from _gh_ost_test_ghc"
)

type Config struct {
Host string
Port int64
Username string
Password string
GhostBinary string
MysqlBinary string
}

type Test struct {
Name string
Path string
CreateSQLFile string
ExtraArgs []string
IgnoreVersions []string
}

func WaitForMySQLAvailable(db *sql.DB) error {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()

for {
select {
case <-time.After(10 * time.Minute):
return errors.New("timed out waiting for mysql")
case <-ticker.C:
if err := db.Ping(); err != nil {
log.Println("Waiting for mysql to become available")
} else {
log.Println("MySQL is available")
return nil
}
}
}
}

// Prepare runs a 'mysql' client/shell command to populate the test schema.
// The create.sql file is read by golang and passed to 'mysql' over stdin.
func (test *Test) Prepare(config Config) error {
if test.CreateSQLFile == "" {
return nil
}

defaultsFile, err := writeMysqlClientDefaultsFile(config)
if err != nil {
return err
}
defer os.Remove(defaultsFile)

flags := []string{
fmt.Sprintf("--defaults-file=%s", defaultsFile),
fmt.Sprintf("--host=%s", PrimaryHost), // TODO: fix this
fmt.Sprintf("--port=%d", config.Port),
"--default-character-set=utf8mb4",
testDatabase,
}
log.Printf("[%s] running command: %s\n %s", test.Name, config.MysqlBinary, strings.Join(flags, "\n "))

createSQL, err := os.Open(test.CreateSQLFile)
if err != nil {
return err
}
defer createSQL.Close()
log.Printf("[%s] loaded sql from: %s", test.Name, test.CreateSQLFile)

cmd := exec.Command(config.MysqlBinary, flags...)
cmd.Stdin = createSQL
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}

func (test *Test) Migrate(db *sql.DB, config Config) error {
mysqlInfo, err := getMysqlHostInfo(db)
if err != nil {
return err
}
log.Printf("[%s] detected MySQL %s host %s:%d", test.Name, mysqlInfo.Version, config.Host, config.Port)

flags := []string{
fmt.Sprintf("--user=%s", config.Username),
fmt.Sprintf("--password=%s", config.Password),
fmt.Sprintf("--host=%s", config.Host),
fmt.Sprintf("--port=%d", config.Port),
fmt.Sprintf("--assume-master-host=primary:%d", mysqlInfo.Port), // TODO: fix this
fmt.Sprintf("--database=%s", testDatabase),
fmt.Sprintf("--table=%s", testTable),
"--assume-rbr",
"--chunk-size=10",
"--default-retries=3",
"--exact-rowcount",
"--initially-drop-old-table",
"--initially-drop-ghost-table",
"--initially-drop-socket-file",
fmt.Sprintf("--throttle-query=%s", throttleQuery),
fmt.Sprintf("--throttle-flag-file=%s", throttleFlagFile),
fmt.Sprintf("--serve-socket-file=%s", testSocketFile),
//"--test-on-replica",
"--allow-on-master",
"--debug",
"--execute",
"--stack",
"--verbose",
}
if len(test.ExtraArgs) > 0 {
flags = append(flags, test.ExtraArgs...)
} else {
flags = append(flags, `--alter='ENGINE=InnoDB'`)
}

log.Printf("[%s] running gh-ost command: %s\n %s", test.Name, config.GhostBinary, strings.Join(flags, "\n "))
cmd := exec.Command(config.GhostBinary, flags...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}

func ReadTests(testsDir string) (tests []Test, err error) {
subdirs, err := ioutil.ReadDir(testsDir)
if err != nil {
return tests, err
}

for _, subdir := range subdirs {
test := Test{
Name: subdir.Name(),
Path: filepath.Join(testsDir, subdir.Name()),
}

stat, err := os.Stat(test.Path)
if err != nil || !stat.IsDir() {
continue
}

test.CreateSQLFile = filepath.Join(test.Path, "create.sql")
if _, err = os.Stat(test.CreateSQLFile); err != nil {
log.Printf("Failed to find create.sql file %q: %+v", test.CreateSQLFile, err)
return tests, err
}

extraArgsFile := filepath.Join(test.Path, "extra_args")
if _, err = os.Stat(extraArgsFile); err == nil {
extraArgsStr, err := readTestFile(extraArgsFile)
if err != nil {
log.Printf("Failed to read extra_args file %q: %+v", extraArgsFile, err)
return tests, err
}
if test.ExtraArgs, err = shlex.Split(extraArgsStr); err != nil {
log.Printf("Failed to read extra_args file %q: %+v", extraArgsFile, err)
return tests, err
}
}

tests = append(tests, test)
}

return tests, err
}

func RunTest(db *sql.DB, config Config, test Test) error {
if err := test.Prepare(config); err != nil {
return err
}
log.Printf("[%s] prepared test", test.Name)

if err := test.Migrate(db, config); err != nil {
return err
}
log.Printf("[%s] migrated test", test.Name)

return nil
}
Loading

0 comments on commit d9ce3ea

Please sign in to comment.