vitess.io/vitess@v0.16.2/go/vt/wrangler/testlib/apply_schema_flaky_test.go (about)

     1  /*
     2  Copyright 2019 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 testlib
    18  
    19  import (
    20  	"strings"
    21  	"testing"
    22  	"time"
    23  
    24  	"vitess.io/vitess/go/vt/discovery"
    25  
    26  	"context"
    27  
    28  	"vitess.io/vitess/go/mysql/fakesqldb"
    29  	"vitess.io/vitess/go/sqltypes"
    30  	"vitess.io/vitess/go/vt/logutil"
    31  	"vitess.io/vitess/go/vt/mysqlctl/tmutils"
    32  	"vitess.io/vitess/go/vt/topo/memorytopo"
    33  	"vitess.io/vitess/go/vt/vttablet/tmclient"
    34  	"vitess.io/vitess/go/vt/wrangler"
    35  
    36  	tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata"
    37  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    38  )
    39  
    40  // TestApplySchema_AllowLongUnavailability is an integration test for the
    41  // --allow_long_unavailability flag of vtctl ApplySchema.
    42  // Only if the flag is specified, potentially long running schema changes are
    43  // allowed.
    44  func TestApplySchema_AllowLongUnavailability(t *testing.T) {
    45  	delay := discovery.GetTabletPickerRetryDelay()
    46  	defer func() {
    47  		discovery.SetTabletPickerRetryDelay(delay)
    48  	}()
    49  	discovery.SetTabletPickerRetryDelay(5 * time.Millisecond)
    50  
    51  	cell := "cell1"
    52  	db := fakesqldb.New(t)
    53  	defer db.Close()
    54  	ts := memorytopo.NewServer(cell)
    55  	wr := wrangler.New(logutil.NewConsoleLogger(), ts, tmclient.NewTabletManagerClient())
    56  	vp := NewVtctlPipe(t, ts)
    57  	defer vp.Close()
    58  
    59  	if err := ts.CreateKeyspace(context.Background(), "ks", &topodatapb.Keyspace{}); err != nil {
    60  		t.Fatalf("CreateKeyspace failed: %v", err)
    61  	}
    62  
    63  	beforeSchema := &tabletmanagerdatapb.SchemaDefinition{
    64  		DatabaseSchema: "CREATE DATABASE `{{.DatabaseName}}` /*!40100 DEFAULT CHARACTER SET utf8 */",
    65  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
    66  			{
    67  				Name:     "table1",
    68  				Schema:   "CREATE TABLE `table1` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `msg` varchar(64) DEFAULT NULL,\n  `keyspace_id` bigint(20) unsigned NOT NULL,\n  PRIMARY KEY (`id`),\n  KEY `by_msg` (`msg`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8",
    69  				Type:     tmutils.TableBaseTable,
    70  				RowCount: 3000000,
    71  			},
    72  		},
    73  	}
    74  	afterSchema := &tabletmanagerdatapb.SchemaDefinition{
    75  		DatabaseSchema: "CREATE DATABASE `{{.DatabaseName}}` /*!40100 DEFAULT CHARACTER SET utf8 */",
    76  		TableDefinitions: []*tabletmanagerdatapb.TableDefinition{
    77  			{
    78  				Name:     "table1",
    79  				Schema:   "CREATE TABLE `table1` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `msg` varchar(64) DEFAULT NULL,\n  `keyspace_id` bigint(20) unsigned NOT NULL,\n  `id` bigint(20),\n  PRIMARY KEY (`id`),\n  KEY `by_msg` (`msg`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8",
    80  				Type:     tmutils.TableBaseTable,
    81  				RowCount: 3000000,
    82  			},
    83  		},
    84  	}
    85  	preflightSchemaChanges := []*tabletmanagerdatapb.SchemaChangeResult{
    86  		{
    87  			BeforeSchema: beforeSchema,
    88  			AfterSchema:  afterSchema,
    89  		},
    90  	}
    91  
    92  	tShard1 := NewFakeTablet(t, wr, cell, 0,
    93  		topodatapb.TabletType_PRIMARY, db, TabletKeyspaceShard(t, "ks", "-80"))
    94  	tShard2 := NewFakeTablet(t, wr, cell, 1,
    95  		topodatapb.TabletType_PRIMARY, db, TabletKeyspaceShard(t, "ks", "80-"))
    96  	for _, ft := range []*FakeTablet{tShard1, tShard2} {
    97  		ft.StartActionLoop(t, wr)
    98  		defer ft.StopActionLoop(t)
    99  
   100  		ft.FakeMysqlDaemon.Schema = beforeSchema
   101  		ft.FakeMysqlDaemon.PreflightSchemaChangeResult = preflightSchemaChanges
   102  	}
   103  
   104  	changeToDb := "USE `vt_ks`"
   105  	addColumn := "ALTER TABLE table1 ADD COLUMN new_id bigint(20)"
   106  	db.AddQuery(changeToDb, &sqltypes.Result{})
   107  	db.AddQuery(addColumn, &sqltypes.Result{})
   108  
   109  	// First ApplySchema fails because the table is very big and -allow_long_unavailability is missing.
   110  	if err := vp.Run([]string{"ApplySchema", "--sql", addColumn, "ks"}); err == nil {
   111  		t.Fatal("ApplySchema should have failed but did not.")
   112  	} else if !strings.Contains(err.Error(), "big schema change detected") ||
   113  		!strings.Contains(strings.ToLower(err.Error()), "alter table table1") {
   114  		t.Fatalf("ApplySchema failed with wrong error. got: %v", err)
   115  	}
   116  
   117  	// Second ApplySchema succeeds because -allow_long_unavailability is set.
   118  	if err := vp.Run([]string{"ApplySchema", "--allow_long_unavailability", "--sql", addColumn, "ks"}); err != nil {
   119  		t.Fatalf("ApplySchema failed: %v", err)
   120  	}
   121  	if count := db.GetQueryCalledNum(changeToDb); count != 2 {
   122  		t.Fatalf("ApplySchema: unexpected call count. Query: %v got: %v want: %v", changeToDb, count, 2)
   123  	}
   124  	if count := db.GetQueryCalledNum(addColumn); count != 2 {
   125  		t.Fatalf("ApplySchema: unexpected call count. Query: %v got: %v want: %v", addColumn, count, 2)
   126  	}
   127  }