vitess.io/vitess@v0.16.2/go/test/endtoend/vtgate/schematracker/sharded/st_sharded_test.go (about)

     1  /*
     2  Copyright 2021 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package sharded
    18  
    19  import (
    20  	"context"
    21  	_ "embed"
    22  	"flag"
    23  	"fmt"
    24  	"os"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/stretchr/testify/assert"
    29  
    30  	"vitess.io/vitess/go/test/endtoend/utils"
    31  	"vitess.io/vitess/go/vt/vtgate/planbuilder"
    32  
    33  	"github.com/stretchr/testify/require"
    34  
    35  	"vitess.io/vitess/go/mysql"
    36  	"vitess.io/vitess/go/test/endtoend/cluster"
    37  )
    38  
    39  var (
    40  	clusterInstance *cluster.LocalProcessCluster
    41  	vtParams        mysql.ConnParams
    42  	KeyspaceName    = "ks"
    43  	Cell            = "test"
    44  	//go:embed schema.sql
    45  	SchemaSQL string
    46  
    47  	//go:embed vschema.json
    48  	VSchema string
    49  )
    50  
    51  func TestMain(m *testing.M) {
    52  	defer cluster.PanicHandler(nil)
    53  	flag.Parse()
    54  
    55  	exitCode := func() int {
    56  		clusterInstance = cluster.NewCluster(Cell, "localhost")
    57  		defer clusterInstance.Teardown()
    58  
    59  		// Start topo server
    60  		err := clusterInstance.StartTopo()
    61  		if err != nil {
    62  			return 1
    63  		}
    64  
    65  		// Start keyspace
    66  		keyspace := &cluster.Keyspace{
    67  			Name:      KeyspaceName,
    68  			SchemaSQL: SchemaSQL,
    69  			VSchema:   VSchema,
    70  		}
    71  		clusterInstance.VtGateExtraArgs = []string{"--schema_change_signal",
    72  			"--vschema_ddl_authorized_users", "%",
    73  			"--schema_change_signal_user", "userData1"}
    74  		clusterInstance.VtGatePlannerVersion = planbuilder.Gen4
    75  		clusterInstance.VtTabletExtraArgs = []string{"--queryserver-config-schema-change-signal",
    76  			"--queryserver-config-schema-change-signal-interval", "0.1",
    77  			"--queryserver-config-strict-table-acl",
    78  			"--queryserver-config-acl-exempt-acl", "userData1",
    79  			"--table-acl-config", "dummy.json"}
    80  
    81  		vtgateVer, err := cluster.GetMajorVersion("vtgate")
    82  		if err != nil {
    83  			return 1
    84  		}
    85  		vttabletVer, err := cluster.GetMajorVersion("vttablet")
    86  		if err != nil {
    87  			return 1
    88  		}
    89  		if vtgateVer >= 16 && vttabletVer >= 16 {
    90  			clusterInstance.VtGateExtraArgs = append(clusterInstance.VtGateExtraArgs, "--enable-views")
    91  			clusterInstance.VtTabletExtraArgs = append(clusterInstance.VtTabletExtraArgs, "--queryserver-enable-views")
    92  		}
    93  
    94  		err = clusterInstance.StartKeyspace(*keyspace, []string{"-80", "80-"}, 0, false)
    95  		if err != nil {
    96  			return 1
    97  		}
    98  
    99  		// Start vtgate
   100  		err = clusterInstance.StartVtgate()
   101  		if err != nil {
   102  			return 1
   103  		}
   104  
   105  		vtParams = mysql.ConnParams{
   106  			Host: clusterInstance.Hostname,
   107  			Port: clusterInstance.VtgateMySQLPort,
   108  		}
   109  		return m.Run()
   110  	}()
   111  	os.Exit(exitCode)
   112  }
   113  
   114  func TestNewTable(t *testing.T) {
   115  	ctx := context.Background()
   116  	conn, err := mysql.Connect(ctx, &vtParams)
   117  	require.NoError(t, err)
   118  	defer conn.Close()
   119  
   120  	shard1Params := vtParams
   121  	shard1Params.DbName += ":-80@primary"
   122  	connShard1, err := mysql.Connect(ctx, &shard1Params)
   123  	require.NoError(t, err)
   124  	defer connShard1.Close()
   125  
   126  	shard2Params := vtParams
   127  	shard2Params.DbName += ":80-@primary"
   128  	connShard2, err := mysql.Connect(ctx, &shard2Params)
   129  	require.NoError(t, err)
   130  	defer connShard2.Close()
   131  
   132  	_ = utils.Exec(t, conn, "create table test_table (id bigint, name varchar(100))")
   133  
   134  	time.Sleep(2 * time.Second)
   135  
   136  	utils.AssertMatches(t, conn, "select * from test_table", `[]`)
   137  	utils.AssertMatches(t, connShard1, "select * from test_table", `[]`)
   138  	utils.AssertMatches(t, connShard2, "select * from test_table", `[]`)
   139  
   140  	utils.Exec(t, conn, "drop table test_table")
   141  
   142  	time.Sleep(2 * time.Second)
   143  }
   144  
   145  func TestAmbiguousColumnJoin(t *testing.T) {
   146  	defer cluster.PanicHandler(t)
   147  	ctx := context.Background()
   148  	conn, err := mysql.Connect(ctx, &vtParams)
   149  	require.NoError(t, err)
   150  	defer conn.Close()
   151  	// this query only works if we know which table the testId belongs to. The vschema does not contain
   152  	// this info, so we are testing that the schema tracker has added column info to the vschema
   153  	_, err = conn.ExecuteFetch(`select testId from t8 join t2`, 1000, true)
   154  	require.NoError(t, err)
   155  }
   156  
   157  func TestInitAndUpdate(t *testing.T) {
   158  	ctx := context.Background()
   159  	conn, err := mysql.Connect(ctx, &vtParams)
   160  	require.NoError(t, err)
   161  	defer conn.Close()
   162  
   163  	vtgateVersion, err := cluster.GetMajorVersion("vtgate")
   164  	require.NoError(t, err)
   165  
   166  	expected := `[[VARCHAR("dual")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]`
   167  	if vtgateVersion >= 17 {
   168  		expected = `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]`
   169  	}
   170  	utils.AssertMatchesWithTimeout(t, conn,
   171  		"SHOW VSCHEMA TABLES",
   172  		expected,
   173  		100*time.Millisecond,
   174  		3*time.Second,
   175  		"initial table list not complete")
   176  
   177  	// Init
   178  	_ = utils.Exec(t, conn, "create table test_sc (id bigint primary key)")
   179  	expected = `[[VARCHAR("dual")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")] [VARCHAR("test_sc")]]`
   180  	if vtgateVersion >= 17 {
   181  		expected = `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")] [VARCHAR("test_sc")]]`
   182  	}
   183  	utils.AssertMatchesWithTimeout(t, conn,
   184  		"SHOW VSCHEMA TABLES",
   185  		expected,
   186  		100*time.Millisecond,
   187  		3*time.Second,
   188  		"test_sc not in vschema tables")
   189  
   190  	// Tables Update via health check.
   191  	_ = utils.Exec(t, conn, "create table test_sc1 (id bigint primary key)")
   192  	expected = `[[VARCHAR("dual")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")] [VARCHAR("test_sc")] [VARCHAR("test_sc1")]]`
   193  	if vtgateVersion >= 17 {
   194  		expected = `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")] [VARCHAR("test_sc")] [VARCHAR("test_sc1")]]`
   195  	}
   196  	utils.AssertMatchesWithTimeout(t, conn,
   197  		"SHOW VSCHEMA TABLES",
   198  		expected,
   199  		100*time.Millisecond,
   200  		3*time.Second,
   201  		"test_sc1 not in vschema tables")
   202  
   203  	_ = utils.Exec(t, conn, "drop table test_sc, test_sc1")
   204  	expected = `[[VARCHAR("dual")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]`
   205  	if vtgateVersion >= 17 {
   206  		expected = `[[VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]`
   207  	}
   208  	utils.AssertMatchesWithTimeout(t, conn,
   209  		"SHOW VSCHEMA TABLES",
   210  		expected,
   211  		100*time.Millisecond,
   212  		3*time.Second,
   213  		"test_sc and test_sc_1 should not be in vschema tables")
   214  
   215  }
   216  
   217  func TestDMLOnNewTable(t *testing.T) {
   218  	ctx := context.Background()
   219  	conn, err := mysql.Connect(ctx, &vtParams)
   220  	require.NoError(t, err)
   221  	defer conn.Close()
   222  
   223  	// create a new table which is not part of the VSchema
   224  	utils.Exec(t, conn, `create table new_table_tracked(id bigint, name varchar(100), primary key(id)) Engine=InnoDB`)
   225  
   226  	vtgateVersion, err := cluster.GetMajorVersion("vtgate")
   227  	require.NoError(t, err)
   228  	expected := `[[VARCHAR("dual")] [VARCHAR("new_table_tracked")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]`
   229  	if vtgateVersion >= 17 {
   230  		expected = `[[VARCHAR("new_table_tracked")] [VARCHAR("t2")] [VARCHAR("t2_id4_idx")] [VARCHAR("t8")]]`
   231  	}
   232  	// wait for vttablet's schema reload interval to pass
   233  	utils.AssertMatchesWithTimeout(t, conn,
   234  		"SHOW VSCHEMA TABLES",
   235  		expected,
   236  		100*time.Millisecond,
   237  		3*time.Second,
   238  		"test_sc not in vschema tables")
   239  
   240  	utils.AssertMatches(t, conn, "select id from new_table_tracked", `[]`)              // select
   241  	utils.AssertMatches(t, conn, "select id from new_table_tracked where id = 5", `[]`) // select
   242  	// DML on new table
   243  	// insert initial data ,update and delete will fail since we have not added a primary vindex
   244  	errorMessage := "table 'new_table_tracked' does not have a primary vindex (errno 1173) (sqlstate 42000)"
   245  	utils.AssertContainsError(t, conn, `insert into new_table_tracked(id) values(0),(1)`, errorMessage)
   246  	utils.AssertContainsError(t, conn, `update new_table_tracked set name = "newName1"`, errorMessage)
   247  	utils.AssertContainsError(t, conn, "delete from new_table_tracked", errorMessage)
   248  
   249  	utils.Exec(t, conn, `select name from new_table_tracked join t8`)
   250  
   251  	// add a primary vindex for the table
   252  	utils.Exec(t, conn, "alter vschema on ks.new_table_tracked add vindex hash(id) using hash")
   253  	time.Sleep(1 * time.Second)
   254  	utils.Exec(t, conn, `insert into new_table_tracked(id) values(0),(1)`)
   255  	utils.Exec(t, conn, `insert into t8(id8) values(2)`)
   256  	defer utils.Exec(t, conn, `delete from t8`)
   257  	utils.AssertMatchesNoOrder(t, conn, `select id from new_table_tracked join t8`, `[[INT64(0)] [INT64(1)]]`)
   258  }
   259  
   260  // TestNewView validates that view tracking works as expected.
   261  func TestNewView(t *testing.T) {
   262  	utils.SkipIfBinaryIsBelowVersion(t, 16, "vtgate")
   263  	utils.SkipIfBinaryIsBelowVersion(t, 16, "vttablet")
   264  
   265  	ctx := context.Background()
   266  	conn, err := mysql.Connect(ctx, &vtParams)
   267  	require.NoError(t, err)
   268  	defer conn.Close()
   269  
   270  	// insert some data
   271  	_ = utils.Exec(t, conn, "insert into t2 (id3, id4) values (1, 10), (2, 20), (3, 30)")
   272  	defer utils.Exec(t, conn, "delete from t2")
   273  
   274  	selQuery := "select sum(id4) from t2 where id4 > 10"
   275  
   276  	// create a view
   277  	_ = utils.Exec(t, conn, "create view test_view as "+selQuery)
   278  
   279  	// executing the query directly
   280  	qr := utils.Exec(t, conn, selQuery)
   281  	// selecting it through the view.
   282  	utils.AssertMatchesWithTimeout(t, conn, "select * from test_view", fmt.Sprintf("%v", qr.Rows), 100*time.Millisecond, 10*time.Second, "test_view not in vschema tables")
   283  }
   284  
   285  // TestViewAndTable validates that new column added in table is present in the view definition
   286  func TestViewAndTable(t *testing.T) {
   287  	utils.SkipIfBinaryIsBelowVersion(t, 16, "vtgate")
   288  	utils.SkipIfBinaryIsBelowVersion(t, 16, "vttablet")
   289  
   290  	ctx := context.Background()
   291  	conn, err := mysql.Connect(ctx, &vtParams)
   292  	require.NoError(t, err)
   293  	defer conn.Close()
   294  
   295  	// add a new column to the table t8
   296  	_ = utils.Exec(t, conn, "alter table t8 add column new_col varchar(50)")
   297  	err = utils.WaitForColumn(t, clusterInstance.VtgateProcess, KeyspaceName, "t8", "new_col")
   298  	require.NoError(t, err)
   299  
   300  	// insert some data
   301  	_ = utils.Exec(t, conn, "insert into t8(id8, new_col) values (1, 'V')")
   302  	defer utils.Exec(t, conn, "delete from t8")
   303  
   304  	// create a view with t8, having the new column.
   305  	_ = utils.Exec(t, conn, "create view t8_view as select * from t8")
   306  
   307  	// executing the view query, with the new column in the select field.
   308  	utils.AssertMatchesWithTimeout(t, conn, "select new_col from t8_view", `[[VARCHAR("V")]]`, 100*time.Millisecond, 5*time.Second, "t8_view not in vschema tables")
   309  
   310  	// add another column to the table t8
   311  	_ = utils.Exec(t, conn, "alter table t8 add column additional_col bigint")
   312  	err = utils.WaitForColumn(t, clusterInstance.VtgateProcess, KeyspaceName, "t8", "additional_col")
   313  	require.NoError(t, err)
   314  
   315  	// executing the query on view
   316  	qr := utils.Exec(t, conn, "select * from t8_view")
   317  	// validate that field name should not have additional_col
   318  	assert.NotContains(t, fmt.Sprintf("%v", qr.Fields), "additional_col")
   319  }