Skip to content

Commit

Permalink
Support optional unit test behavior for 5.7
Browse files Browse the repository at this point in the history
Signed-off-by: Matt Lord <[email protected]>
  • Loading branch information
mattlord committed Dec 14, 2024
1 parent eb3f1b0 commit 91b1e33
Show file tree
Hide file tree
Showing 12 changed files with 114 additions and 28 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/unit_test_evalengine_mysql57.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ jobs:
export NOVTADMINBUILD=1
export VTEVALENGINETEST="1"
# We sometimes need to alter the behavior based on the platform we're
# testing, e.g. MySQL 5.7 vs 8.0.
export CI_DB_PLATFORM="mysql57"
eatmydata -- make unit_test | tee -a output.txt | go-junit-report -set-exit-code > report.xml
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/unit_test_evalengine_mysql80.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ jobs:
export NOVTADMINBUILD=1
export VTEVALENGINETEST="1"
# We sometimes need to alter the behavior based on the platform we're
# testing, e.g. MySQL 5.7 vs 8.0.
export CI_DB_PLATFORM="mysql80"
eatmydata -- make unit_test | tee -a output.txt | go-junit-report -set-exit-code > report.xml
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/unit_test_evalengine_mysql84.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ jobs:
export NOVTADMINBUILD=1
export VTEVALENGINETEST="1"
# We sometimes need to alter the behavior based on the platform we're
# testing, e.g. MySQL 5.7 vs 8.0.
export CI_DB_PLATFORM="mysql84"
eatmydata -- make unit_test | tee -a output.txt | go-junit-report -set-exit-code > report.xml
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/unit_test_mysql57.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ jobs:
export NOVTADMINBUILD=1
export VTEVALENGINETEST="0"
# We sometimes need to alter the behavior based on the platform we're
# testing, e.g. MySQL 5.7 vs 8.0.
export CI_DB_PLATFORM="mysql57"
eatmydata -- make unit_test | tee -a output.txt | go-junit-report -set-exit-code > report.xml
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/unit_test_mysql80.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ jobs:
export NOVTADMINBUILD=1
export VTEVALENGINETEST="0"
# We sometimes need to alter the behavior based on the platform we're
# testing, e.g. MySQL 5.7 vs 8.0.
export CI_DB_PLATFORM="mysql80"
eatmydata -- make unit_test | tee -a output.txt | go-junit-report -set-exit-code > report.xml
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/unit_test_mysql84.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ jobs:
export NOVTADMINBUILD=1
export VTEVALENGINETEST="0"
# We sometimes need to alter the behavior based on the platform we're
# testing, e.g. MySQL 5.7 vs 8.0.
export CI_DB_PLATFORM="mysql84"
eatmydata -- make unit_test | tee -a output.txt | go-junit-report -set-exit-code > report.xml
Expand Down
12 changes: 8 additions & 4 deletions go/test/endtoend/vreplication/vreplication_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,10 @@ func testVreplicationWorkflows(t *testing.T, limited bool, binlogRowImage string
defer func() { defaultReplicas = 1 }()

if binlogRowImage != "" {
require.NoError(t, utils.SetBinlogRowImageMode("noblob", vc.ClusterConfig.tmpDir))
defer utils.SetBinlogRowImageMode("", vc.ClusterConfig.tmpDir)
// Run the e2e test with binlog_row_image=NOBLOB and
// binlog_row_value_options=PARTIAL_JSON.
require.NoError(t, utils.SetBinlogRowImageMode("noblob", vc.ClusterConfig.tmpDir, true))
defer utils.SetBinlogRowImageMode("", vc.ClusterConfig.tmpDir, false)
}

defaultCell := vc.Cells[defaultCellName]
Expand Down Expand Up @@ -600,8 +602,10 @@ func TestCellAliasVreplicationWorkflow(t *testing.T) {
keyspace := "product"
shard := "0"

require.NoError(t, utils.SetBinlogRowImageMode("noblob", vc.ClusterConfig.tmpDir))
defer utils.SetBinlogRowImageMode("", vc.ClusterConfig.tmpDir)
// Run the e2e test with binlog_row_image=NOBLOB and
// binlog_row_value_options=PARTIAL_JSON.
require.NoError(t, utils.SetBinlogRowImageMode("noblob", vc.ClusterConfig.tmpDir, true))
defer utils.SetBinlogRowImageMode("", vc.ClusterConfig.tmpDir, false)

cell1 := vc.Cells["zone1"]
cell2 := vc.Cells["zone2"]
Expand Down
43 changes: 38 additions & 5 deletions go/test/utils/binlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package utils
import (
"fmt"
"os"
"strconv"
"strings"
)

Expand All @@ -28,9 +29,11 @@ const (
)

// SetBinlogRowImageMode creates a temp cnf file to set binlog_row_image=NOBLOB and
// binlog_row_value_options=PARTIAL_JSON for vreplication unit tests.
// It adds it to the EXTRA_MY_CNF environment variable which appends text from them into my.cnf.
func SetBinlogRowImageMode(mode string, cnfDir string) error {
// optionally binlog_row_value_options=PARTIAL_JSON (since it does not exist in 5.7)
// for vreplication unit tests.
// It adds it to the EXTRA_MY_CNF environment variable which appends text from them
// into my.cnf.
func SetBinlogRowImageMode(mode string, cnfDir string, includePartialJSON bool) error {
var newCnfs []string

// remove any existing extra cnfs for binlog row image
Expand All @@ -56,8 +59,10 @@ func SetBinlogRowImageMode(mode string, cnfDir string) error {
if err != nil {
return err
}
lm := strings.ToLower(mode)
if lm == "noblob" || lm == "minimal" {
if includePartialJSON {
if !CIDBPlatformIsMySQL8orLater() {
return fmt.Errorf("partial JSON values are only supported in MySQL 8.0 or later")
}
// We're testing partial binlog row images so let's also test partial
// JSON values in the images.
_, err = f.WriteString("\nbinlog_row_value_options=PARTIAL_JSON\n")
Expand All @@ -78,3 +83,31 @@ func SetBinlogRowImageMode(mode string, cnfDir string) error {
}
return nil
}

// CIDBPlatformIsMySQL8orLater returns true if the CI_DB_PLATFORM environment
// variable is empty -- meaning we're not running in the CI and we assume
// MySQL8.0 or later is used, and you can understand the failures and make
// adjustments as necessary -- or it's set to reflect usage of MySQL 8.0 or
// later. This relies on the current standard values used such as mysql5.7,
// mysql8.0, mysql8.4, mariadb10.7, etc. This can be used when the CI test
// behavior needs to be altered based on the specific database platform
// we're testing against.
func CIDBPlatformIsMySQL8orLater() bool {
dbPlatform := strings.ToLower(os.Getenv("CI_DB_PLATFORM"))
if dbPlatform == "" {
// This is for local testing where we don't set the env var via
// the CI.
return true
}
if strings.HasPrefix(dbPlatform, "mysql") {
_, v, ok := strings.Cut(dbPlatform, "mysql")
if ok {
// We only want the major version.
version, err := strconv.Atoi(string(v[0]))
if err == nil && version >= 8 {
return true
}
}
}
return false
}
16 changes: 14 additions & 2 deletions go/test/utils/binlog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,27 @@ import (
func TestUtils(t *testing.T) {
tmpDir := "/tmp"
cnfFile := fmt.Sprintf("%s/%s", tmpDir, BinlogRowImageCnf)

// Test that setting the mode will create the cnf file and add it to the EXTRA_MY_CNF env var.
require.NoError(t, SetBinlogRowImageMode("noblob", tmpDir))
require.NoError(t, SetBinlogRowImageMode("noblob", tmpDir, false))
data, err := os.ReadFile(cnfFile)
require.NoError(t, err)
require.Contains(t, string(data), "binlog_row_image=noblob")
require.Contains(t, os.Getenv(ExtraCnf), BinlogRowImageCnf)

// Test that setting the mode and passing true for includePartialJSON will set both options
// as expected.
if CIDBPlatformIsMySQL8orLater() {
require.NoError(t, SetBinlogRowImageMode("noblob", tmpDir, true))
data, err = os.ReadFile(cnfFile)
require.NoError(t, err)
require.Contains(t, string(data), "binlog_row_image=noblob")
require.Contains(t, string(data), "binlog_row_value_options=PARTIAL_JSON")
require.Contains(t, os.Getenv(ExtraCnf), BinlogRowImageCnf)
}

// Test that clearing the mode will remove the cnf file and the cnf from the EXTRA_MY_CNF env var.
require.NoError(t, SetBinlogRowImageMode("", tmpDir))
require.NoError(t, SetBinlogRowImageMode("", tmpDir, false))
require.NotContains(t, os.Getenv(ExtraCnf), BinlogRowImageCnf)
_, err = os.Stat(cnfFile)
require.True(t, os.IsNotExist(err))
Expand Down
21 changes: 15 additions & 6 deletions go/vt/vttablet/tabletmanager/vreplication/framework_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,13 @@ func setup(ctx context.Context) (func(), int) {
return cleanup, 0
}

// We run Tests twice, first with full binlog_row_image, then with noblob.
var runNoBlobTest = false
var (
// We run unit tests twice, first with binlog_row_image=FULL, then with NOBLOB.
runNoBlobTest = false
// When using MySQL 8.0 or later, we also set binlog_row_value_options=PARTIAL_JSON
// when using NOBLOB.
runPartialJSONTest = false
)

// We use this tempDir for creating the external cnfs, since we create the test cluster afterwards.
const tempDir = "/tmp"
Expand All @@ -178,10 +183,10 @@ func TestMain(m *testing.M) {
exitCode := func() int {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if err := utils.SetBinlogRowImageMode("full", tempDir); err != nil {
if err := utils.SetBinlogRowImageMode("full", tempDir, false); err != nil {
panic(err)
}
defer utils.SetBinlogRowImageMode("", tempDir)
defer utils.SetBinlogRowImageMode("", tempDir, false)
cancel, ret := setup(ctx)
if ret > 0 {
return ret
Expand All @@ -193,10 +198,14 @@ func TestMain(m *testing.M) {
cancel()

runNoBlobTest = true
if err := utils.SetBinlogRowImageMode("noblob", tempDir); err != nil {
// binlog-row-value-options=PARTIAL_JSON is only supported in MySQL 8.0 and later.
// We still run unit tests with MySQL 5.7, so we cannot add it to the cnf file
// when using 5.7 or mysqld will fail to start.
runPartialJSONTest = utils.CIDBPlatformIsMySQL8orLater()
if err := utils.SetBinlogRowImageMode("noblob", tempDir, runPartialJSONTest); err != nil {
panic(err)
}
defer utils.SetBinlogRowImageMode("", tempDir)
defer utils.SetBinlogRowImageMode("", tempDir, false)
cancel, ret = setup(ctx)
if ret > 0 {
return ret
Expand Down
29 changes: 18 additions & 11 deletions go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1521,12 +1521,18 @@ func TestPlayerRowMove(t *testing.T) {

// TestPlayerPartialImagesUpdatePK tests the behavior of the vplayer when we
// have partial binlog images, meaning that binlog-row-image=NOBLOB and
// binlog-row-value-options=PARTIAL_JSON. These are both set together when
// running the unit tests with runNoBlobTest=true. So we skip the test if
// it's not set.
// binlog-row-value-options=PARTIAL_JSON. These are both set when running the
// unit tests with runNoBlobTest=true and runPartialJSONTest=true.
// If the test is running in the CI and the database platform is not MySQL
// 8.0 or later (which you can control using the CI_DB_PLATFORM env variable),
// then runPartialJSONTest will be false and the test will be skipped.
// the test if it's not set.
func TestPlayerPartialImagesUpdatePK(t *testing.T) {
if !runNoBlobTest {
t.Skip("Skipping test as runNoBlobTest is not set")
t.Skip("Skipping test as binlog_row_image=NOBLOB is not set")
}
if !runPartialJSONTest {
t.Skip("Skipping test as binlog-row-value-options=PARTIAL_JSON is not set (most likely because the database type is not MySQL 8.0 or later)")
}

defer deleteTablet(addTablet(100))
Expand Down Expand Up @@ -1554,12 +1560,13 @@ func TestPlayerPartialImagesUpdatePK(t *testing.T) {
cancel, _ := startVReplication(t, bls, "")
defer cancel()

testCases := []struct {
type testCase struct {
input string
output []string
data [][]string
error string
}{
}
testCases := []testCase{
{
input: "insert into src (id, jd, bd) values (1,'{\"key1\": \"val1\"}','blob data'), (2,'{\"key2\": \"val2\"}','blob data2'), (3,'{\"key3\": \"val3\"}','blob data3')",
output: []string{"insert into dst(id,jd,bd) values (1,JSON_OBJECT(_utf8mb4'key1', _utf8mb4'val1'),_binary'blob data'), (2,JSON_OBJECT(_utf8mb4'key2', _utf8mb4'val2'),_binary'blob data2'), (3,JSON_OBJECT(_utf8mb4'key3', _utf8mb4'val3'),_binary'blob data3')"},
Expand Down Expand Up @@ -1757,22 +1764,22 @@ func TestPlayerTypes(t *testing.T) {
{"2", "null", `{"name": null}`, "123", `{"a": [42, 100]}`, `{"foo": "bar"}`},
},
}}
if !runNoBlobTest {
if runNoBlobTest && runPartialJSONTest {
// With partial JSON values we don't replicate the JSON columns that aren't
// actually updated.
testcases = append(testcases, testcase{
input: "update vitess_json set val1 = '{\"bar\": \"foo\"}', val4 = '{\"a\": [98, 123]}', val5 = convert(x'7b7d' using utf8mb4) where id=1",
output: "update vitess_json set val1=JSON_OBJECT(_utf8mb4'bar', _utf8mb4'foo'), val2=JSON_OBJECT(), val3=CAST(123 as JSON), val4=JSON_OBJECT(_utf8mb4'a', JSON_ARRAY(98, 123)), val5=JSON_OBJECT() where id=1",
output: "update vitess_json set val1=JSON_OBJECT(_utf8mb4'bar', _utf8mb4'foo'), val4=JSON_OBJECT(_utf8mb4'a', JSON_ARRAY(98, 123)), val5=JSON_OBJECT() where id=1",
table: "vitess_json",
data: [][]string{
{"1", `{"bar": "foo"}`, "{}", "123", `{"a": [98, 123]}`, `{}`},
{"2", "null", `{"name": null}`, "123", `{"a": [42, 100]}`, `{"foo": "bar"}`},
},
})
} else {
// With partial JSON values we don't replicate the JSON columns that aren't
// actually updated.
testcases = append(testcases, testcase{
input: "update vitess_json set val1 = '{\"bar\": \"foo\"}', val4 = '{\"a\": [98, 123]}', val5 = convert(x'7b7d' using utf8mb4) where id=1",
output: "update vitess_json set val1=JSON_OBJECT(_utf8mb4'bar', _utf8mb4'foo'), val4=JSON_OBJECT(_utf8mb4'a', JSON_ARRAY(98, 123)), val5=JSON_OBJECT() where id=1",
output: "update vitess_json set val1=JSON_OBJECT(_utf8mb4'bar', _utf8mb4'foo'), val2=JSON_OBJECT(), val3=CAST(123 as JSON), val4=JSON_OBJECT(_utf8mb4'a', JSON_ARRAY(98, 123)), val5=JSON_OBJECT() where id=1",
table: "vitess_json",
data: [][]string{
{"1", `{"bar": "foo"}`, "{}", "123", `{"a": [98, 123]}`, `{}`},
Expand Down
3 changes: 3 additions & 0 deletions test/templates/unit_test.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ jobs:

export NOVTADMINBUILD=1
export VTEVALENGINETEST="{{.Evalengine}}"
# We sometimes need to alter the behavior based on the platform we're
# testing, e.g. MySQL 5.7 vs 8.0.
export CI_DB_PLATFORM="{{.Platform}}"

eatmydata -- make unit_test | tee -a output.txt | go-junit-report -set-exit-code > report.xml

Expand Down

0 comments on commit 91b1e33

Please sign in to comment.