vitess.io/vitess@v0.16.2/go/test/endtoend/topotest/consul/main_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 consul
    18  
    19  import (
    20  	"context"
    21  	"flag"
    22  	"fmt"
    23  	"os"
    24  	"testing"
    25  	"time"
    26  
    27  	"vitess.io/vitess/go/vt/log"
    28  
    29  	"github.com/google/go-cmp/cmp"
    30  	"github.com/stretchr/testify/require"
    31  
    32  	"vitess.io/vitess/go/mysql"
    33  	"vitess.io/vitess/go/sqltypes"
    34  	"vitess.io/vitess/go/test/endtoend/cluster"
    35  )
    36  
    37  var (
    38  	clusterInstance *cluster.LocalProcessCluster
    39  	cell            = "zone1"
    40  	hostname        = "localhost"
    41  	KeyspaceName    = "customer"
    42  	SchemaSQL       = `
    43  CREATE TABLE t1 (
    44      c1 BIGINT NOT NULL,
    45      c2 BIGINT NOT NULL,
    46      c3 BIGINT,
    47      c4 varchar(100),
    48      PRIMARY KEY (c1),
    49      UNIQUE KEY (c2),
    50      UNIQUE KEY (c3),
    51      UNIQUE KEY (c4)
    52  ) ENGINE=Innodb;`
    53  	VSchema = `
    54  {
    55      "sharded": false,
    56      "tables": {
    57          "t1": {}
    58      }
    59  }
    60  `
    61  )
    62  
    63  func TestMain(m *testing.M) {
    64  	defer cluster.PanicHandler(nil)
    65  	flag.Parse()
    66  
    67  	exitCode := func() int {
    68  		clusterInstance = cluster.NewCluster(cell, hostname)
    69  		defer clusterInstance.Teardown()
    70  
    71  		// Start topo server
    72  		clusterInstance.TopoFlavor = "consul"
    73  		if err := clusterInstance.StartTopo(); err != nil {
    74  			return 1
    75  		}
    76  
    77  		// Start keyspace
    78  		Keyspace := &cluster.Keyspace{
    79  			Name:      KeyspaceName,
    80  			SchemaSQL: SchemaSQL,
    81  			VSchema:   VSchema,
    82  		}
    83  		if err := clusterInstance.StartUnshardedKeyspace(*Keyspace, 0, false); err != nil {
    84  			log.Fatal(err.Error())
    85  			return 1
    86  		}
    87  
    88  		// Start vtgate
    89  		if err := clusterInstance.StartVtgate(); err != nil {
    90  			log.Fatal(err.Error())
    91  			return 1
    92  		}
    93  
    94  		return m.Run()
    95  	}()
    96  	os.Exit(exitCode)
    97  }
    98  
    99  func TestTopoRestart(t *testing.T) {
   100  	defer cluster.PanicHandler(t)
   101  	ctx := context.Background()
   102  	vtParams := mysql.ConnParams{
   103  		Host: "localhost",
   104  		Port: clusterInstance.VtgateMySQLPort,
   105  	}
   106  	conn, err := mysql.Connect(ctx, &vtParams)
   107  	require.Nil(t, err)
   108  	defer conn.Close()
   109  
   110  	execMulti(t, conn, `insert into t1(c1, c2, c3, c4) values (300,100,300,'abc'); ;; insert into t1(c1, c2, c3, c4) values (301,101,301,'abcd');;`)
   111  	assertMatches(t, conn, `select c1,c2,c3 from t1`, `[[INT64(300) INT64(100) INT64(300)] [INT64(301) INT64(101) INT64(301)]]`)
   112  
   113  	defer execute(t, conn, `delete from t1`)
   114  
   115  	ch := make(chan any)
   116  
   117  	go func() {
   118  		clusterInstance.TopoProcess.TearDown(clusterInstance.Cell, clusterInstance.OriginalVTDATAROOT, clusterInstance.CurrentVTDATAROOT, true, *clusterInstance.TopoFlavorString())
   119  
   120  		// Some sleep to server few queries when topo is down.
   121  		time.Sleep(400 * time.Millisecond)
   122  
   123  		clusterInstance.TopoProcess.Setup(*clusterInstance.TopoFlavorString(), clusterInstance)
   124  
   125  		// topo is up now.
   126  		ch <- 1
   127  	}()
   128  
   129  	timeOut := time.After(15 * time.Second)
   130  
   131  	for {
   132  		select {
   133  		case <-ch:
   134  			return
   135  		case <-timeOut:
   136  			require.Fail(t, "timed out - topo process did not come up")
   137  		case <-time.After(100 * time.Millisecond):
   138  			assertMatches(t, conn, `select c1,c2,c3 from t1`, `[[INT64(300) INT64(100) INT64(300)] [INT64(301) INT64(101) INT64(301)]]`)
   139  		}
   140  	}
   141  }
   142  
   143  func execute(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result {
   144  	t.Helper()
   145  	qr, err := conn.ExecuteFetch(query, 1000, true)
   146  	require.NoError(t, err)
   147  	return qr
   148  }
   149  
   150  func execMulti(t *testing.T, conn *mysql.Conn, query string) []*sqltypes.Result {
   151  	t.Helper()
   152  	var res []*sqltypes.Result
   153  	qr, more, err := conn.ExecuteFetchMulti(query, 1000, true)
   154  	res = append(res, qr)
   155  	require.NoError(t, err)
   156  	for more == true {
   157  		qr, more, _, err = conn.ReadQueryResult(1000, true)
   158  		require.NoError(t, err)
   159  		res = append(res, qr)
   160  	}
   161  	return res
   162  }
   163  
   164  func assertMatches(t *testing.T, conn *mysql.Conn, query, expected string) {
   165  	t.Helper()
   166  	qr := execute(t, conn, query)
   167  	got := fmt.Sprintf("%v", qr.Rows)
   168  	diff := cmp.Diff(expected, got)
   169  	if diff != "" {
   170  		t.Errorf("Query: %s (-want +got):\n%s", query, diff)
   171  	}
   172  }