vitess.io/vitess@v0.16.2/go/vt/vtgr/controller/refresh_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 controller
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"sort"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/golang/mock/gomock"
    27  	"github.com/stretchr/testify/assert"
    28  
    29  	"vitess.io/vitess/go/vt/logutil"
    30  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    31  	"vitess.io/vitess/go/vt/topo"
    32  	"vitess.io/vitess/go/vt/topo/memorytopo"
    33  	"vitess.io/vitess/go/vt/vtctl/grpcvtctldserver/testutil"
    34  	"vitess.io/vitess/go/vt/vtgr/config"
    35  )
    36  
    37  func TestRefreshTabletsInShard(t *testing.T) {
    38  	ctrl := gomock.NewController(t)
    39  	defer ctrl.Finish()
    40  	ctx := context.Background()
    41  	ts := memorytopo.NewServer("test_cell")
    42  	defer ts.Close()
    43  	ts.CreateKeyspace(ctx, "ks", &topodatapb.Keyspace{})
    44  	ts.CreateShard(ctx, "ks", "0")
    45  	tablet1 := buildTabletInfo(uint32(0), testHost, testPort0, topodatapb.TabletType_PRIMARY, time.Time{})
    46  	tablet2 := buildTabletInfo(uint32(1), testHost, testPort1, topodatapb.TabletType_SPARE, time.Time{})
    47  	tablet3 := buildTabletInfo(uint32(2), testHost, 0, topodatapb.TabletType_REPLICA, time.Time{})
    48  	testutil.AddTablet(ctx, t, ts, tablet1.Tablet, nil)
    49  	testutil.AddTablet(ctx, t, ts, tablet2.Tablet, nil)
    50  	testutil.AddTablet(ctx, t, ts, tablet3.Tablet, nil)
    51  	cfg := &config.VTGRConfig{BootstrapGroupSize: 3, MinNumReplica: 0, BackoffErrorWaitTimeSeconds: 1, BootstrapWaitTimeSeconds: 1}
    52  	shard := NewGRShard("ks", "0", nil, nil, ts, nil, cfg, testPort0, true)
    53  	assert.Equal(t, "ks", shard.shardStatusCollector.status.Keyspace)
    54  	assert.Equal(t, "0", shard.shardStatusCollector.status.Shard)
    55  	shard.refreshTabletsInShardLocked(context.Background())
    56  	instances := shard.instances
    57  	// only have 2 instances here because we filter out the spare tablet
    58  	assert.Equal(t, 2, len(instances))
    59  	sort.Slice(instances[:], func(i, j int) bool {
    60  		return instances[i].alias < instances[j].alias
    61  	})
    62  	assert.Equal(t, testHost, instances[0].tablet.Hostname)
    63  	assert.Equal(t, int32(testPort0), instances[0].tablet.MysqlPort)
    64  	assert.Equal(t, topodatapb.TabletType_PRIMARY, instances[0].tablet.Type)
    65  	// host 3 is missing mysql host but we still put it in the instances list here
    66  	assert.Equal(t, testHost, instances[1].instanceKey.Hostname)
    67  	assert.Equal(t, int32(0), instances[1].tablet.MysqlPort)
    68  	assert.Equal(t, topodatapb.TabletType_REPLICA, instances[1].tablet.Type)
    69  }
    70  
    71  func TestRefreshWithCells(t *testing.T) {
    72  	ctx := context.Background()
    73  	ts := memorytopo.NewServer("cell1", "cell2", "cell3")
    74  	defer ts.Close()
    75  	ts.CreateKeyspace(ctx, "ks", &topodatapb.Keyspace{})
    76  	ts.CreateShard(ctx, "ks", "0")
    77  	tablet1 := buildTabletInfoWithCell(uint32(0), testHost, "cell1", testPort0, topodatapb.TabletType_REPLICA, time.Time{})
    78  	tablet2 := buildTabletInfoWithCell(uint32(1), testHost, "cell2", testPort1, topodatapb.TabletType_REPLICA, time.Time{})
    79  	tablet3 := buildTabletInfoWithCell(uint32(2), testHost, "cell3", testPort2, topodatapb.TabletType_REPLICA, time.Time{})
    80  	testutil.AddTablet(ctx, t, ts, tablet1.Tablet, nil)
    81  	testutil.AddTablet(ctx, t, ts, tablet2.Tablet, nil)
    82  	testutil.AddTablet(ctx, t, ts, tablet3.Tablet, nil)
    83  	cfg := &config.VTGRConfig{BootstrapGroupSize: 3, MinNumReplica: 0, BackoffErrorWaitTimeSeconds: 1, BootstrapWaitTimeSeconds: 1}
    84  	shard := NewGRShard("ks", "0", []string{"cell1", "cell3"}, nil, ts, nil, cfg, testPort0, true)
    85  	shard.refreshTabletsInShardLocked(context.Background())
    86  	instances := shard.instances
    87  	// only have 2 instances here because we are not watching cell2
    88  	assert.Equal(t, 2, len(instances))
    89  	sort.Slice(instances[:], func(i, j int) bool {
    90  		return instances[i].alias < instances[j].alias
    91  	})
    92  	assert.Equal(t, "cell1-0000000000", instances[0].alias)
    93  	assert.Equal(t, "cell3-0000000002", instances[1].alias)
    94  }
    95  
    96  func TestRefreshWithEmptyCells(t *testing.T) {
    97  	ctx := context.Background()
    98  	ts := memorytopo.NewServer("cell1", "cell2", "cell3")
    99  	defer ts.Close()
   100  	ts.CreateKeyspace(ctx, "ks", &topodatapb.Keyspace{})
   101  	ts.CreateShard(ctx, "ks", "0")
   102  	tablet1 := buildTabletInfoWithCell(uint32(0), testHost, "cell1", testPort0, topodatapb.TabletType_REPLICA, time.Time{})
   103  	tablet2 := buildTabletInfoWithCell(uint32(1), testHost, "cell2", testPort1, topodatapb.TabletType_REPLICA, time.Time{})
   104  	tablet3 := buildTabletInfoWithCell(uint32(2), testHost, "cell3", testPort2, topodatapb.TabletType_REPLICA, time.Time{})
   105  	testutil.AddTablet(ctx, t, ts, tablet1.Tablet, nil)
   106  	testutil.AddTablet(ctx, t, ts, tablet2.Tablet, nil)
   107  	testutil.AddTablet(ctx, t, ts, tablet3.Tablet, nil)
   108  	cfg := &config.VTGRConfig{BootstrapGroupSize: 3, MinNumReplica: 0, BackoffErrorWaitTimeSeconds: 1, BootstrapWaitTimeSeconds: 1}
   109  	shard := NewGRShard("ks", "0", nil, nil, ts, nil, cfg, testPort0, true)
   110  	shard.refreshTabletsInShardLocked(context.Background())
   111  	instances := shard.instances
   112  	// nil cell will return everything
   113  	assert.Equal(t, 3, len(instances))
   114  	sort.Slice(instances[:], func(i, j int) bool {
   115  		return instances[i].alias < instances[j].alias
   116  	})
   117  	assert.Equal(t, "cell1-0000000000", instances[0].alias)
   118  	assert.Equal(t, "cell2-0000000001", instances[1].alias)
   119  	assert.Equal(t, "cell3-0000000002", instances[2].alias)
   120  }
   121  
   122  func TestLockRelease(t *testing.T) {
   123  	ctx := context.Background()
   124  	ts := memorytopo.NewServer("cell1", "cell2", "cell3")
   125  	defer ts.Close()
   126  	ts.CreateKeyspace(ctx, "ks", &topodatapb.Keyspace{})
   127  	ts.CreateShard(ctx, "ks", "0")
   128  	cfg := &config.VTGRConfig{BootstrapGroupSize: 3, MinNumReplica: 0, BackoffErrorWaitTimeSeconds: 1, BootstrapWaitTimeSeconds: 1}
   129  	shard := NewGRShard("ks", "0", nil, nil, ts, nil, cfg, testPort0, true)
   130  	ctx, err := shard.LockShard(ctx, "")
   131  	assert.NoError(t, err)
   132  	// make sure we get the lock
   133  	err = shard.checkShardLocked(ctx)
   134  	assert.NoError(t, err)
   135  	assert.NotNil(t, shard.unlock)
   136  	shard.UnlockShard()
   137  	assert.Nil(t, shard.unlock)
   138  	err = shard.checkShardLocked(ctx)
   139  	assert.EqualError(t, err, "lost topology lock; aborting: shard ks/0 is not locked (no lockInfo in map)")
   140  }
   141  
   142  func buildTabletInfo(id uint32, host string, mysqlPort int, ttype topodatapb.TabletType, primaryTermTime time.Time) *topo.TabletInfo {
   143  	return buildTabletInfoWithCell(id, host, "test_cell", mysqlPort, ttype, primaryTermTime)
   144  }
   145  
   146  func buildTabletInfoWithCell(id uint32, host, cell string, mysqlPort int, ttype topodatapb.TabletType, primaryTermTime time.Time) *topo.TabletInfo {
   147  	alias := &topodatapb.TabletAlias{Cell: cell, Uid: id}
   148  	return &topo.TabletInfo{Tablet: &topodatapb.Tablet{
   149  		Alias:                alias,
   150  		Hostname:             host,
   151  		MysqlHostname:        host,
   152  		MysqlPort:            int32(mysqlPort),
   153  		Keyspace:             "ks",
   154  		Shard:                "0",
   155  		Type:                 ttype,
   156  		PrimaryTermStartTime: logutil.TimeToProto(primaryTermTime),
   157  		Tags:                 map[string]string{"hostname": fmt.Sprintf("host_%d", id)},
   158  	}}
   159  }