Skip to content

Commit df4cf7b

Browse files
Add basic test for hooks (#1179)
1 parent 1df37c2 commit df4cf7b

File tree

4 files changed

+120
-19
lines changed

4 files changed

+120
-19
lines changed

go/logic/hooks.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package logic
77

88
import (
99
"fmt"
10+
"io"
1011
"os"
1112
"os/exec"
1213
"path/filepath"
@@ -34,18 +35,16 @@ const (
3435

3536
type HooksExecutor struct {
3637
migrationContext *base.MigrationContext
38+
writer io.Writer
3739
}
3840

3941
func NewHooksExecutor(migrationContext *base.MigrationContext) *HooksExecutor {
4042
return &HooksExecutor{
4143
migrationContext: migrationContext,
44+
writer: os.Stderr,
4245
}
4346
}
4447

45-
func (this *HooksExecutor) initHooks() error {
46-
return nil
47-
}
48-
4948
func (this *HooksExecutor) applyEnvironmentVariables(extraVariables ...string) []string {
5049
env := os.Environ()
5150
env = append(env, fmt.Sprintf("GH_OST_DATABASE_NAME=%s", this.migrationContext.DatabaseName))
@@ -76,13 +75,13 @@ func (this *HooksExecutor) applyEnvironmentVariables(extraVariables ...string) [
7675
}
7776

7877
// executeHook executes a command, and sets relevant environment variables
79-
// combined output & error are printed to gh-ost's standard error.
78+
// combined output & error are printed to the configured writer.
8079
func (this *HooksExecutor) executeHook(hook string, extraVariables ...string) error {
8180
cmd := exec.Command(hook)
8281
cmd.Env = this.applyEnvironmentVariables(extraVariables...)
8382

8483
combinedOutput, err := cmd.CombinedOutput()
85-
fmt.Fprintln(os.Stderr, string(combinedOutput))
84+
fmt.Fprintln(this.writer, string(combinedOutput))
8685
return log.Errore(err)
8786
}
8887

go/logic/hooks_test.go

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
Copyright 2022 GitHub Inc.
3+
See https://github.com/github/gh-ost/blob/master/LICENSE
4+
*/
5+
6+
package logic
7+
8+
import (
9+
"bufio"
10+
"bytes"
11+
"fmt"
12+
"os"
13+
"path/filepath"
14+
"strconv"
15+
"strings"
16+
"testing"
17+
"time"
18+
19+
"github.com/openark/golib/tests"
20+
21+
"github.com/github/gh-ost/go/base"
22+
)
23+
24+
func TestHooksExecutorExecuteHooks(t *testing.T) {
25+
migrationContext := base.NewMigrationContext()
26+
migrationContext.AlterStatement = "ENGINE=InnoDB"
27+
migrationContext.DatabaseName = "test"
28+
migrationContext.Hostname = "test.example.com"
29+
migrationContext.OriginalTableName = "tablename"
30+
migrationContext.RowsDeltaEstimate = 1
31+
migrationContext.RowsEstimate = 122
32+
migrationContext.TotalRowsCopied = 123456
33+
migrationContext.SetETADuration(time.Minute)
34+
migrationContext.SetProgressPct(50)
35+
hooksExecutor := NewHooksExecutor(migrationContext)
36+
37+
writeTmpHookFunc := func(testName, hookName, script string) (path string, err error) {
38+
if path, err = os.MkdirTemp("", testName); err != nil {
39+
return path, err
40+
}
41+
err = os.WriteFile(filepath.Join(path, hookName), []byte(script), 0777)
42+
return path, err
43+
}
44+
45+
t.Run("does-not-exist", func(t *testing.T) {
46+
migrationContext.HooksPath = "/does/not/exist"
47+
tests.S(t).ExpectNil(hooksExecutor.executeHooks("test-hook"))
48+
})
49+
50+
t.Run("failed", func(t *testing.T) {
51+
var err error
52+
if migrationContext.HooksPath, err = writeTmpHookFunc(
53+
"TestHooksExecutorExecuteHooks-failed",
54+
"failed-hook",
55+
"#!/bin/sh\nexit 1",
56+
); err != nil {
57+
panic(err)
58+
}
59+
defer os.RemoveAll(migrationContext.HooksPath)
60+
tests.S(t).ExpectNotNil(hooksExecutor.executeHooks("failed-hook"))
61+
})
62+
63+
t.Run("success", func(t *testing.T) {
64+
var err error
65+
if migrationContext.HooksPath, err = writeTmpHookFunc(
66+
"TestHooksExecutorExecuteHooks-success",
67+
"success-hook",
68+
"#!/bin/sh\nenv",
69+
); err != nil {
70+
panic(err)
71+
}
72+
defer os.RemoveAll(migrationContext.HooksPath)
73+
74+
var buf bytes.Buffer
75+
hooksExecutor.writer = &buf
76+
tests.S(t).ExpectNil(hooksExecutor.executeHooks("success-hook", "TEST="+t.Name()))
77+
78+
scanner := bufio.NewScanner(&buf)
79+
for scanner.Scan() {
80+
split := strings.SplitN(scanner.Text(), "=", 2)
81+
switch split[0] {
82+
case "GH_OST_COPIED_ROWS":
83+
copiedRows, _ := strconv.ParseInt(split[1], 10, 64)
84+
tests.S(t).ExpectEquals(copiedRows, migrationContext.TotalRowsCopied)
85+
case "GH_OST_DATABASE_NAME":
86+
tests.S(t).ExpectEquals(split[1], migrationContext.DatabaseName)
87+
case "GH_OST_DDL":
88+
tests.S(t).ExpectEquals(split[1], migrationContext.AlterStatement)
89+
case "GH_OST_DRY_RUN":
90+
tests.S(t).ExpectEquals(split[1], "false")
91+
case "GH_OST_ESTIMATED_ROWS":
92+
estimatedRows, _ := strconv.ParseInt(split[1], 10, 64)
93+
tests.S(t).ExpectEquals(estimatedRows, int64(123))
94+
case "GH_OST_ETA_SECONDS":
95+
etaSeconds, _ := strconv.ParseInt(split[1], 10, 64)
96+
tests.S(t).ExpectEquals(etaSeconds, int64(60))
97+
case "GH_OST_EXECUTING_HOST":
98+
tests.S(t).ExpectEquals(split[1], migrationContext.Hostname)
99+
case "GH_OST_GHOST_TABLE_NAME":
100+
tests.S(t).ExpectEquals(split[1], fmt.Sprintf("_%s_gho", migrationContext.OriginalTableName))
101+
case "GH_OST_OLD_TABLE_NAME":
102+
tests.S(t).ExpectEquals(split[1], fmt.Sprintf("_%s_del", migrationContext.OriginalTableName))
103+
case "GH_OST_PROGRESS":
104+
progress, _ := strconv.ParseFloat(split[1], 64)
105+
tests.S(t).ExpectEquals(progress, 50.0)
106+
case "GH_OST_TABLE_NAME":
107+
tests.S(t).ExpectEquals(split[1], migrationContext.OriginalTableName)
108+
case "TEST":
109+
tests.S(t).ExpectEquals(split[1], t.Name())
110+
}
111+
}
112+
})
113+
}

go/logic/migrator.go

+1-12
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ type Migrator struct {
9898
func NewMigrator(context *base.MigrationContext, appVersion string) *Migrator {
9999
migrator := &Migrator{
100100
appVersion: appVersion,
101+
hooksExecutor: NewHooksExecutor(context),
101102
migrationContext: context,
102103
parser: sql.NewAlterTableParser(),
103104
ghostTableMigrated: make(chan bool),
@@ -113,15 +114,6 @@ func NewMigrator(context *base.MigrationContext, appVersion string) *Migrator {
113114
return migrator
114115
}
115116

116-
// initiateHooksExecutor
117-
func (this *Migrator) initiateHooksExecutor() (err error) {
118-
this.hooksExecutor = NewHooksExecutor(this.migrationContext)
119-
if err := this.hooksExecutor.initHooks(); err != nil {
120-
return err
121-
}
122-
return nil
123-
}
124-
125117
// sleepWhileTrue sleeps indefinitely until the given function returns 'false'
126118
// (or fails with error)
127119
func (this *Migrator) sleepWhileTrue(operation func() (bool, error)) error {
@@ -342,9 +334,6 @@ func (this *Migrator) Migrate() (err error) {
342334

343335
go this.listenOnPanicAbort()
344336

345-
if err := this.initiateHooksExecutor(); err != nil {
346-
return err
347-
}
348337
if err := this.hooksExecutor.onStartup(); err != nil {
349338
return err
350339
}

script/test

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ script/build
1414
cd .gopath/src/github.com/github/gh-ost
1515

1616
echo "Running unit tests"
17-
go test ./go/...
17+
go test -v -covermode=atomic ./go/...

0 commit comments

Comments
 (0)