Skip to content

Commit

Permalink
Fix Foreign key fuzzer to ignore rows affected (#15841)
Browse files Browse the repository at this point in the history
  • Loading branch information
GuptaManan100 authored May 7, 2024
1 parent 4f90a87 commit 9bfc18c
Show file tree
Hide file tree
Showing 11 changed files with 53 additions and 31 deletions.
12 changes: 6 additions & 6 deletions go/test/endtoend/utils/cmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func (mcmp *MySQLCompare) AssertMatchesAnyNoCompare(query string, expected ...st
// Both clients need to return an error. The error of Vitess must be matching the given expectation.
func (mcmp *MySQLCompare) AssertContainsError(query, expected string) {
mcmp.t.Helper()
_, err := mcmp.ExecAllowAndCompareError(query)
_, err := mcmp.ExecAllowAndCompareError(query, CompareOptions{})
require.Error(mcmp.t, err)
assert.Contains(mcmp.t, err.Error(), expected, "actual error: %s", err.Error())
}
Expand Down Expand Up @@ -211,7 +211,7 @@ func (mcmp *MySQLCompare) Exec(query string) *sqltypes.Result {

mysqlQr, err := mcmp.MySQLConn.ExecuteFetch(query, 1000, true)
require.NoError(mcmp.t, err, "[MySQL Error] for query: "+query)
compareVitessAndMySQLResults(mcmp.t, query, mcmp.VtConn, vtQr, mysqlQr, false)
compareVitessAndMySQLResults(mcmp.t, query, mcmp.VtConn, vtQr, mysqlQr, CompareOptions{})
return vtQr
}

Expand All @@ -238,7 +238,7 @@ func (mcmp *MySQLCompare) ExecWithColumnCompare(query string) *sqltypes.Result {

mysqlQr, err := mcmp.MySQLConn.ExecuteFetch(query, 1000, true)
require.NoError(mcmp.t, err, "[MySQL Error] for query: "+query)
compareVitessAndMySQLResults(mcmp.t, query, mcmp.VtConn, vtQr, mysqlQr, true)
compareVitessAndMySQLResults(mcmp.t, query, mcmp.VtConn, vtQr, mysqlQr, CompareOptions{CompareColumnNames: true})
return vtQr
}

Expand All @@ -250,7 +250,7 @@ func (mcmp *MySQLCompare) ExecWithColumnCompare(query string) *sqltypes.Result {
// The result set and error produced by Vitess are returned to the caller.
// If the Vitess and MySQL error are both nil, but the results do not match,
// the mismatched results are instead returned as an error, as well as the Vitess result set
func (mcmp *MySQLCompare) ExecAllowAndCompareError(query string) (*sqltypes.Result, error) {
func (mcmp *MySQLCompare) ExecAllowAndCompareError(query string, opts CompareOptions) (*sqltypes.Result, error) {
mcmp.t.Helper()
vtQr, vtErr := mcmp.VtConn.ExecuteFetch(query, 1000, true)
mysqlQr, mysqlErr := mcmp.MySQLConn.ExecuteFetch(query, 1000, true)
Expand All @@ -259,7 +259,7 @@ func (mcmp *MySQLCompare) ExecAllowAndCompareError(query string) (*sqltypes.Resu
// Since we allow errors, we don't want to compare results if one of the client failed.
// Vitess and MySQL should always be agreeing whether the query returns an error or not.
if vtErr == nil && mysqlErr == nil {
vtErr = compareVitessAndMySQLResults(mcmp.t, query, mcmp.VtConn, vtQr, mysqlQr, false)
vtErr = compareVitessAndMySQLResults(mcmp.t, query, mcmp.VtConn, vtQr, mysqlQr, opts)
}
return vtQr, vtErr
}
Expand Down Expand Up @@ -297,7 +297,7 @@ func (mcmp *MySQLCompare) ExecAllowError(query string) (*sqltypes.Result, error)
// Since we allow errors, we don't want to compare results if one of the client failed.
// Vitess and MySQL should always be agreeing whether the query returns an error or not.
if mysqlErr == nil {
vtErr = compareVitessAndMySQLResults(mcmp.t, query, mcmp.VtConn, vtQr, mysqlQr, false)
vtErr = compareVitessAndMySQLResults(mcmp.t, query, mcmp.VtConn, vtQr, mysqlQr, CompareOptions{})
}
return vtQr, vtErr
}
14 changes: 12 additions & 2 deletions go/test/endtoend/utils/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,12 @@ func prepareMySQLWithSchema(params mysql.ConnParams, sql string) error {
return nil
}

func compareVitessAndMySQLResults(t TestingT, query string, vtConn *mysql.Conn, vtQr, mysqlQr *sqltypes.Result, compareColumnNames bool) error {
type CompareOptions struct {
CompareColumnNames bool
IgnoreRowsAffected bool
}

func compareVitessAndMySQLResults(t TestingT, query string, vtConn *mysql.Conn, vtQr, mysqlQr *sqltypes.Result, opts CompareOptions) error {
t.Helper()

if vtQr == nil && mysqlQr == nil {
Expand Down Expand Up @@ -203,7 +208,7 @@ func compareVitessAndMySQLResults(t TestingT, query string, vtConn *mysql.Conn,
myCols = append(myCols, myField.Name)
}

if compareColumnNames && !assert.Equal(t, myCols, vtCols, "column names do not match - the expected values are what mysql produced") {
if opts.CompareColumnNames && !assert.Equal(t, myCols, vtCols, "column names do not match - the expected values are what mysql produced") {
t.Errorf("column names do not match - the expected values are what mysql produced\nNot equal: \nexpected: %v\nactual: %v\n", myCols, vtCols)
}
}
Expand All @@ -218,6 +223,11 @@ func compareVitessAndMySQLResults(t TestingT, query string, vtConn *mysql.Conn,
orderBy = selStmt.GetOrderBy() != nil
}

if opts.IgnoreRowsAffected {
vtQr.RowsAffected = 0
mysqlQr.RowsAffected = 0
}

if (orderBy && sqltypes.ResultsEqual([]sqltypes.Result{*vtQr}, []sqltypes.Result{*mysqlQr})) || sqltypes.ResultsEqualUnordered([]sqltypes.Result{*vtQr}, []sqltypes.Result{*mysqlQr}) {
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion go/test/endtoend/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func ExecCompareMySQL(t *testing.T, vtConn, mysqlConn *mysql.Conn, query string)

mysqlQr, err := mysqlConn.ExecuteFetch(query, 1000, true)
require.NoError(t, err, "[MySQL Error] for query: "+query)
compareVitessAndMySQLResults(t, query, vtConn, vtQr, mysqlQr, false)
compareVitessAndMySQLResults(t, query, vtConn, vtQr, mysqlQr, CompareOptions{})
return vtQr
}

Expand Down
2 changes: 1 addition & 1 deletion go/test/endtoend/vtgate/foreignkey/fk_fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ func (fz *fuzzer) generateAndExecuteStatementQuery(t *testing.T, mcmp utils.MySQ
for _, query := range queries {
// When the concurrency is 1, then we run the query both on MySQL and Vitess.
if fz.concurrency == 1 {
_, _ = mcmp.ExecAllowAndCompareError(query)
_, _ = mcmp.ExecAllowAndCompareError(query, utils.CompareOptions{IgnoreRowsAffected: true})
// If t is marked failed, we have encountered our first failure.
// Let's collect the required information and finish execution.
if t.Failed() {
Expand Down
22 changes: 17 additions & 5 deletions go/test/endtoend/vtgate/foreignkey/fk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,7 @@ func TestFkScenarios(t *testing.T) {
}

// Run the DML query that needs to be tested and verify output with MySQL.
_, err := mcmp.ExecAllowAndCompareError(tt.dmlQuery)
_, err := mcmp.ExecAllowAndCompareError(tt.dmlQuery, utils.CompareOptions{})
if tt.dmlShouldErr {
assert.Error(t, err)
} else {
Expand Down Expand Up @@ -948,7 +948,7 @@ func TestFkScenarios(t *testing.T) {
mcmp.Exec("SELECT * FROM fk_t13 ORDER BY id")

// Update that fails
_, err := mcmp.ExecAllowAndCompareError("UPDATE fk_t10 SET col = 15 WHERE id = 1")
_, err := mcmp.ExecAllowAndCompareError("UPDATE fk_t10 SET col = 15 WHERE id = 1", utils.CompareOptions{})
require.Error(t, err)

// Verify the results
Expand Down Expand Up @@ -1006,6 +1006,7 @@ func TestFkQueries(t *testing.T) {
testcases := []struct {
name string
queries []string
opts utils.CompareOptions
}{
{
name: "Non-literal update",
Expand Down Expand Up @@ -1135,6 +1136,17 @@ func TestFkQueries(t *testing.T) {
"delete fk_t11 from fk_t11 join fk_t12 using (id) where fk_t11.id = 4",
},
},
{
name: "Multi table delete where MySQL and Vitess report different rows affected",
queries: []string{
"insert /*+ SET_VAR(foreign_key_checks=0) */ into fk_t11 (id, col) values (4, '1'), (5, '3'), (7, '22'), (8, '5'), (9, NULL), (10, '3')",
"insert /*+ SET_VAR(foreign_key_checks=0) */ into fk_t12 (id, col) values (4, '1'), (5, '3'), (7, '22'), (8, '5'), (9, NULL), (10, '3')",
"delete fk_t11, fk_t12 from fk_t11 join fk_t12 using (id) where fk_t11.id = 5",
},
opts: utils.CompareOptions{
IgnoreRowsAffected: true,
},
},
}

for _, tt := range testcases {
Expand All @@ -1153,7 +1165,7 @@ func TestFkQueries(t *testing.T) {
ensureDatabaseState(t, mcmp.MySQLConn, true)

for _, query := range tt.queries {
_, _ = mcmp.ExecAllowAndCompareError(query)
_, _ = mcmp.ExecAllowAndCompareError(query, tt.opts)
if t.Failed() {
break
}
Expand Down Expand Up @@ -1212,7 +1224,7 @@ func TestFkOneCase(t *testing.T) {
log.Errorf("Query %v, Result - %v", query, res.Rows)
continue
}
_, _ = mcmp.ExecAllowAndCompareError(query)
_, _ = mcmp.ExecAllowAndCompareError(query, utils.CompareOptions{})
if t.Failed() {
log.Errorf("Query failed - %v", query)
break
Expand Down Expand Up @@ -1490,5 +1502,5 @@ create table temp2(id bigint auto_increment primary key, col varchar(20) not nul
mcmp.Exec(`set foreign_key_checks = on`)
mcmp.Exec(`insert into temp2(col) values('a'), ('b'), ('c') `)
mcmp.Exec(`insert into temp1(col) values('a') `)
mcmp.ExecAllowAndCompareError(`insert into temp1(col) values('d') `)
mcmp.ExecAllowAndCompareError(`insert into temp1(col) values('d') `, utils.CompareOptions{})
}
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,7 @@ func TestHavingQueries(t *testing.T) {

for _, query := range queries {
mcmp.Run(query, func(mcmp *utils.MySQLCompare) {
mcmp.ExecAllowAndCompareError(query)
mcmp.ExecAllowAndCompareError(query, utils.CompareOptions{})
})
}
}
2 changes: 1 addition & 1 deletion go/test/endtoend/vtgate/queries/dml/dml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ func TestDeleteWithSubquery(t *testing.T) {
`[[INT64(1) INT64(1) INT64(4)] [INT64(1) INT64(2) INT64(2)] [INT64(2) INT64(3) INT64(5)]]`)

// delete with subquery from same table (fails on mysql) - subquery get's merged so fails for vitess
_, err := mcmp.ExecAllowAndCompareError(`delete from s_tbl where id in (select id from s_tbl)`)
_, err := mcmp.ExecAllowAndCompareError(`delete from s_tbl where id in (select id from s_tbl)`, utils.CompareOptions{})
require.ErrorContains(t, err, "You can't specify target table 's_tbl' for update in FROM clause (errno 1093) (sqlstate HY000)")

// delete with subquery from same table (fails on mysql) - subquery not merged so passes for vitess
Expand Down
16 changes: 8 additions & 8 deletions go/test/endtoend/vtgate/queries/misc/misc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ func TestInvalidDateTimeTimestampVals(t *testing.T) {
mcmp, closer := start(t)
defer closer()

_, err := mcmp.ExecAllowAndCompareError(`select date'2022'`)
_, err := mcmp.ExecAllowAndCompareError(`select date'2022'`, utils.CompareOptions{})
require.Error(t, err)
_, err = mcmp.ExecAllowAndCompareError(`select time'12:34:56:78'`)
_, err = mcmp.ExecAllowAndCompareError(`select time'12:34:56:78'`, utils.CompareOptions{})
require.Error(t, err)
_, err = mcmp.ExecAllowAndCompareError(`select timestamp'2022'`)
_, err = mcmp.ExecAllowAndCompareError(`select timestamp'2022'`, utils.CompareOptions{})
require.Error(t, err)
}

Expand Down Expand Up @@ -257,12 +257,12 @@ func TestPrepareStatements(t *testing.T) {
mcmp.AssertMatchesNoOrder(`execute prep_in_pk using @id1, @id2`, `[[INT64(0) INT64(0)] [INT64(1) INT64(0)]]`)

// Fail by providing wrong number of arguments
_, err := mcmp.ExecAllowAndCompareError(`execute prep_in_pk using @id1, @id1, @id`)
_, err := mcmp.ExecAllowAndCompareError(`execute prep_in_pk using @id1, @id1, @id`, utils.CompareOptions{})
incorrectCount := "VT03025: Incorrect arguments to EXECUTE"
assert.ErrorContains(t, err, incorrectCount)
_, err = mcmp.ExecAllowAndCompareError(`execute prep_in_pk using @id1`)
_, err = mcmp.ExecAllowAndCompareError(`execute prep_in_pk using @id1`, utils.CompareOptions{})
assert.ErrorContains(t, err, incorrectCount)
_, err = mcmp.ExecAllowAndCompareError(`execute prep_in_pk`)
_, err = mcmp.ExecAllowAndCompareError(`execute prep_in_pk`, utils.CompareOptions{})
assert.ErrorContains(t, err, incorrectCount)

mcmp.Exec(`prepare prep_art from 'select 1+?, 10/?'`)
Expand All @@ -282,10 +282,10 @@ func TestPrepareStatements(t *testing.T) {
mcmp.Exec(`select 1+9999999999999999999999999999, 10/9999999999999999999999999999 from t1 limit 1`)

mcmp.Exec("deallocate prepare prep_art")
_, err = mcmp.ExecAllowAndCompareError(`execute prep_art using @id1, @id1`)
_, err = mcmp.ExecAllowAndCompareError(`execute prep_art using @id1, @id1`, utils.CompareOptions{})
assert.ErrorContains(t, err, "VT09011: Unknown prepared statement handler (prep_art) given to EXECUTE")

_, err = mcmp.ExecAllowAndCompareError("deallocate prepare prep_art")
_, err = mcmp.ExecAllowAndCompareError("deallocate prepare prep_art", utils.CompareOptions{})
assert.ErrorContains(t, err, "VT09011: Unknown prepared statement handler (prep_art) given to DEALLOCATE PREPARE")
}

Expand Down
2 changes: 1 addition & 1 deletion go/test/endtoend/vtgate/queries/orderby/orderby_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func TestOrderByComplex(t *testing.T) {

for _, query := range queries {
mcmp.Run(query, func(mcmp *utils.MySQLCompare) {
_, _ = mcmp.ExecAllowAndCompareError(query)
_, _ = mcmp.ExecAllowAndCompareError(query, utils.CompareOptions{})
})
}
}
4 changes: 2 additions & 2 deletions go/test/endtoend/vtgate/queries/random/random_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func helperTest(t *testing.T, query string) {
mcmp, closer := start(t)
defer closer()

result, err := mcmp.ExecAllowAndCompareError(query)
result, err := mcmp.ExecAllowAndCompareError(query, utils.CompareOptions{})
fmt.Println(result)
fmt.Println(err)
})
Expand Down Expand Up @@ -261,7 +261,7 @@ func TestRandom(t *testing.T) {
qg := newQueryGenerator(genConfig, 2, 2, 2, schemaTables)
qg.randomQuery()
query := sqlparser.String(qg.stmt)
_, vtErr := mcmp.ExecAllowAndCompareError(query)
_, vtErr := mcmp.ExecAllowAndCompareError(query, utils.CompareOptions{})

// this assumes all queries are valid mysql queries
if vtErr != nil {
Expand Down
6 changes: 3 additions & 3 deletions go/test/endtoend/vtgate/queries/random/simplifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func TestSimplifyResultsMismatchedQuery(t *testing.T) {
mcmp, closer := start(t)
defer closer()

mcmp.ExecAllowAndCompareError(simplified)
mcmp.ExecAllowAndCompareError(simplified, utils.CompareOptions{})
})

fmt.Printf("final simplified query: %s\n", simplified)
Expand All @@ -77,7 +77,7 @@ func simplifyResultsMismatchedQuery(t *testing.T, query string) string {
mcmp, closer := start(t)
defer closer()

_, err := mcmp.ExecAllowAndCompareError(query)
_, err := mcmp.ExecAllowAndCompareError(query, utils.CompareOptions{})
if err == nil {
t.Fatalf("query (%s) does not error", query)
} else if !strings.Contains(err.Error(), "mismatched") {
Expand Down Expand Up @@ -105,7 +105,7 @@ func simplifyResultsMismatchedQuery(t *testing.T, query string) string {
vSchemaWrapper,
func(statement sqlparser.SelectStatement) bool {
q := sqlparser.String(statement)
_, newErr := mcmp.ExecAllowAndCompareError(q)
_, newErr := mcmp.ExecAllowAndCompareError(q, utils.CompareOptions{})
if newErr == nil {
return false
} else {
Expand Down

0 comments on commit 9bfc18c

Please sign in to comment.