vitess.io/vitess@v0.16.2/go/test/endtoend/versionupgrade/upgrade_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  /*
    18  
    19  ABOUT THIS TEST
    20  ===============
    21  
    22  This test plays part in testing an upgrade path from a previous version/tag. It takes a GitHub workflow file to complete the functionality.
    23  What's in this file is the setting up of a cluster, sharded and unsharded keyspace, creating and populating some tables, then testing retrieval of data.
    24  The twist here is that you can run this test over pre-existing vtdataroot, which means this test can reuse existing etcd, existing tables, existing mysql,
    25  in which case it will not attempt to create keyspaces/schemas/tables, nor will it populate table data. Instead, it will only check for retrieval of data.
    26  
    27  The game is to setup the cluster with a stable version (say `v8.0.0`), take it down (and preserve data), then setup a new cluster with a new version (namely the branch/PR head) and attempt to read the data.
    28  
    29  Both executions must force some settings so that both reuse same directories, ports, etc. An invocation will look like:
    30  go test ./go/test/endtoend/versionupgrade80/upgrade_test.go --keep-data --force-vtdataroot /tmp/vtdataroot/vtroot_10901 --force-port-start 11900 --force-base-tablet-uid 1190
    31  
    32  */
    33  
    34  package versionupgrade
    35  
    36  import (
    37  	"flag"
    38  	"fmt"
    39  	"os"
    40  	"path"
    41  	"testing"
    42  
    43  	"github.com/stretchr/testify/assert"
    44  	"github.com/stretchr/testify/require"
    45  
    46  	"vitess.io/vitess/go/mysql"
    47  	"vitess.io/vitess/go/test/endtoend/cluster"
    48  )
    49  
    50  var (
    51  	clusterInstance       *cluster.LocalProcessCluster
    52  	vtParams              mysql.ConnParams
    53  	hostname              = "localhost"
    54  	keyspaceName          = "ks"
    55  	cell                  = "zone1"
    56  	schemaChangeDirectory = ""
    57  	totalTableCount       = 4
    58  	createTable           = `
    59  		CREATE TABLE %s (
    60  			id bigint(20) NOT NULL,
    61  			msg varchar(64),
    62  			PRIMARY KEY (id)
    63  		) ENGINE=InnoDB;
    64  		`
    65  	insertIntoTable = `
    66  		INSERT INTO %s (id, msg) VALUES (17, 'abc');
    67  		`
    68  	selectFromTable = `
    69  		SELECT id, msg FROM %s LIMIT 1;
    70  		`
    71  )
    72  
    73  // TestMain is the main entry point
    74  func TestMain(m *testing.M) {
    75  	defer cluster.PanicHandler(nil)
    76  	flag.Parse()
    77  
    78  	exitcode, err := func() (int, error) {
    79  		clusterInstance = cluster.NewCluster(cell, hostname)
    80  		schemaChangeDirectory = path.Join("/tmp", fmt.Sprintf("schema_change_dir_%d", clusterInstance.GetAndReserveTabletUID()))
    81  		defer os.RemoveAll(schemaChangeDirectory)
    82  		defer clusterInstance.Teardown()
    83  
    84  		if _, err := os.Stat(schemaChangeDirectory); os.IsNotExist(err) {
    85  			_ = os.Mkdir(schemaChangeDirectory, 0700)
    86  		}
    87  
    88  		clusterInstance.VtctldExtraArgs = []string{
    89  			"--schema_change_dir", schemaChangeDirectory,
    90  			"--schema_change_controller", "local",
    91  			"--schema_change_check_interval", "1"}
    92  
    93  		if err := clusterInstance.StartTopo(); err != nil {
    94  			return 1, err
    95  		}
    96  
    97  		// Start keyspace
    98  		keyspace := &cluster.Keyspace{
    99  			Name: keyspaceName,
   100  		}
   101  
   102  		if err := clusterInstance.StartUnshardedKeyspaceLegacy(*keyspace, 2, true); err != nil {
   103  			return 1, err
   104  		}
   105  		if err := clusterInstance.StartKeyspaceLegacy(*keyspace, []string{"1"}, 1, false); err != nil {
   106  			return 1, err
   107  		}
   108  
   109  		// TODO: remove this once we upgrade to v12
   110  		// setting the planner version to 0, so the vtgate binary's default is used
   111  		clusterInstance.VtGatePlannerVersion = 0
   112  		vtgateInstance := clusterInstance.NewVtgateInstance()
   113  		// Start vtgate
   114  		if err := vtgateInstance.Setup(); err != nil {
   115  			return 1, err
   116  		}
   117  		// ensure it is torn down during cluster TearDown
   118  		clusterInstance.VtgateProcess = *vtgateInstance
   119  		vtParams = mysql.ConnParams{
   120  			Host: clusterInstance.Hostname,
   121  			Port: clusterInstance.VtgateMySQLPort,
   122  		}
   123  
   124  		return m.Run(), nil
   125  	}()
   126  	if err != nil {
   127  		fmt.Printf("%v\n", err)
   128  		os.Exit(1)
   129  	} else {
   130  		os.Exit(exitcode)
   131  	}
   132  
   133  }
   134  
   135  func TestShards(t *testing.T) {
   136  	defer cluster.PanicHandler(t)
   137  	assert.Equal(t, 2, len(clusterInstance.Keyspaces[0].Shards))
   138  }
   139  
   140  func TestDeploySchema(t *testing.T) {
   141  	defer cluster.PanicHandler(t)
   142  
   143  	if clusterInstance.ReusingVTDATAROOT {
   144  		// we assume data is already deployed
   145  		return
   146  	}
   147  	// Create n tables, populate
   148  	for i := 0; i < totalTableCount; i++ {
   149  		tableName := fmt.Sprintf("vt_upgrade_test_%02d", i)
   150  
   151  		{
   152  			sqlQuery := fmt.Sprintf(createTable, tableName)
   153  			result, err := clusterInstance.VtctlclientProcess.ApplySchemaWithOutput(keyspaceName, sqlQuery, cluster.VtctlClientParams{DDLStrategy: ""})
   154  			require.Nil(t, err, result)
   155  		}
   156  		for i := range clusterInstance.Keyspaces[0].Shards {
   157  			sqlQuery := fmt.Sprintf(insertIntoTable, tableName)
   158  			tablet := clusterInstance.Keyspaces[0].Shards[i].Vttablets[0]
   159  			_, err := tablet.VttabletProcess.QueryTablet(sqlQuery, keyspaceName, true)
   160  			require.Nil(t, err)
   161  		}
   162  	}
   163  
   164  	checkTables(t, "", totalTableCount)
   165  }
   166  
   167  func TestTablesExist(t *testing.T) {
   168  	defer cluster.PanicHandler(t)
   169  
   170  	checkTables(t, "", totalTableCount)
   171  }
   172  
   173  // checkTables checks the number of tables in the first two shards.
   174  func checkTables(t *testing.T, showTableName string, expectCount int) {
   175  	for i := range clusterInstance.Keyspaces[0].Shards {
   176  		checkTablesCount(t, clusterInstance.Keyspaces[0].Shards[i].Vttablets[0], showTableName, expectCount)
   177  	}
   178  }
   179  
   180  // checkTablesCount checks the number of tables in the given tablet
   181  func checkTablesCount(t *testing.T, tablet *cluster.Vttablet, showTableName string, expectCount int) {
   182  	query := fmt.Sprintf(`show tables like '%%%s%%';`, showTableName)
   183  	queryResult, err := tablet.VttabletProcess.QueryTablet(query, keyspaceName, true)
   184  	require.Nil(t, err)
   185  	assert.Equal(t, expectCount, len(queryResult.Rows))
   186  }
   187  
   188  // TestTablesData checks the data in tables
   189  func TestTablesData(t *testing.T) {
   190  	// Create n tables, populate
   191  	for i := 0; i < totalTableCount; i++ {
   192  		tableName := fmt.Sprintf("vt_upgrade_test_%02d", i)
   193  
   194  		for i := range clusterInstance.Keyspaces[0].Shards {
   195  			sqlQuery := fmt.Sprintf(selectFromTable, tableName)
   196  			tablet := clusterInstance.Keyspaces[0].Shards[i].Vttablets[0]
   197  			queryResult, err := tablet.VttabletProcess.QueryTablet(sqlQuery, keyspaceName, true)
   198  			require.Nil(t, err)
   199  			require.NotNil(t, queryResult)
   200  			row := queryResult.Named().Row()
   201  			require.NotNil(t, row)
   202  			require.Equal(t, int64(17), row.AsInt64("id", 0))
   203  			require.Equal(t, "abc", row.AsString("msg", ""))
   204  		}
   205  	}
   206  }