vitess.io/vitess@v0.16.2/go/vt/topo/topotests/cell_info_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 topotests
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"strings"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/require"
    28  
    29  	"vitess.io/vitess/go/vt/topo"
    30  	"vitess.io/vitess/go/vt/topo/memorytopo"
    31  
    32  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    33  )
    34  
    35  // This file tests the CellInfo part of the topo.Server API.
    36  
    37  func TestCellInfo(t *testing.T) {
    38  	cell := "cell1"
    39  	ctx := context.Background()
    40  	ts := memorytopo.NewServer(cell)
    41  
    42  	// Check GetCellInfo returns what memorytopo created.
    43  	ci, err := ts.GetCellInfo(ctx, cell, true /*strongRead*/)
    44  	if err != nil {
    45  		t.Fatalf("GetCellInfo failed: %v", err)
    46  	}
    47  	if ci.Root != "" {
    48  		t.Fatalf("unexpected CellInfo: %v", ci)
    49  	}
    50  
    51  	var cells []string
    52  	cells, err = ts.ExpandCells(ctx, cell)
    53  	require.NoError(t, err)
    54  	require.EqualValues(t, []string{"cell1"}, cells)
    55  
    56  	// Update the Server Address.
    57  	if err := ts.UpdateCellInfoFields(ctx, cell, func(ci *topodatapb.CellInfo) error {
    58  		ci.ServerAddress = "new address"
    59  		return nil
    60  	}); err != nil {
    61  		t.Fatalf("UpdateCellInfoFields failed: %v", err)
    62  	}
    63  	ci, err = ts.GetCellInfo(ctx, cell, true /*strongRead*/)
    64  	if err != nil {
    65  		t.Fatalf("GetCellInfo failed: %v", err)
    66  	}
    67  	if ci.ServerAddress != "new address" {
    68  		t.Fatalf("unexpected CellInfo: %v", ci)
    69  	}
    70  
    71  	// Test update with no change.
    72  	if err := ts.UpdateCellInfoFields(ctx, cell, func(ci *topodatapb.CellInfo) error {
    73  		ci.ServerAddress = "bad address"
    74  		return topo.NewError(topo.NoUpdateNeeded, cell)
    75  	}); err != nil {
    76  		t.Fatalf("UpdateCellInfoFields failed: %v", err)
    77  	}
    78  	ci, err = ts.GetCellInfo(ctx, cell, true /*strongRead*/)
    79  	if err != nil {
    80  		t.Fatalf("GetCellInfo failed: %v", err)
    81  	}
    82  	if ci.ServerAddress != "new address" {
    83  		t.Fatalf("unexpected CellInfo: %v", ci)
    84  	}
    85  
    86  	// Test failing update.
    87  	updateErr := fmt.Errorf("inside error")
    88  	if err := ts.UpdateCellInfoFields(ctx, cell, func(ci *topodatapb.CellInfo) error {
    89  		return updateErr
    90  	}); err != updateErr {
    91  		t.Fatalf("UpdateCellInfoFields failed: %v", err)
    92  	}
    93  
    94  	// Test update on non-existing object.
    95  	newCell := "new_cell"
    96  	if err := ts.UpdateCellInfoFields(ctx, newCell, func(ci *topodatapb.CellInfo) error {
    97  		ci.Root = "/"
    98  		ci.ServerAddress = "good address"
    99  		return nil
   100  	}); err != nil {
   101  		t.Fatalf("UpdateCellInfoFields failed: %v", err)
   102  	}
   103  	ci, err = ts.GetCellInfo(ctx, newCell, true /*strongRead*/)
   104  	if err != nil {
   105  		t.Fatalf("GetCellInfo failed: %v", err)
   106  	}
   107  	if ci.ServerAddress != "good address" || ci.Root != "/" {
   108  		t.Fatalf("unexpected CellInfo: %v", ci)
   109  	}
   110  
   111  	// Add a record that should block CellInfo deletion for safety reasons.
   112  	if err := ts.UpdateSrvKeyspace(ctx, cell, "keyspace", &topodatapb.SrvKeyspace{}); err != nil {
   113  		t.Fatalf("UpdateSrvKeyspace failed: %v", err)
   114  	}
   115  	srvKeyspaces, err := ts.GetSrvKeyspaceNames(ctx, cell)
   116  	if err != nil {
   117  		t.Fatalf("GetSrvKeyspaceNames failed: %v", err)
   118  	}
   119  	if len(srvKeyspaces) == 0 {
   120  		t.Fatalf("UpdateSrvKeyspace did not add SrvKeyspace.")
   121  	}
   122  
   123  	// Try to delete without force; it should fail.
   124  	if err := ts.DeleteCellInfo(ctx, cell, false); err == nil {
   125  		t.Fatalf("DeleteCellInfo should have failed without -force")
   126  	}
   127  
   128  	// Use the force.
   129  	if err := ts.DeleteCellInfo(ctx, cell, true); err != nil {
   130  		t.Fatalf("DeleteCellInfo failed even with -force: %v", err)
   131  	}
   132  	if _, err := ts.GetCellInfo(ctx, cell, true /*strongRead*/); !topo.IsErrType(err, topo.NoNode) {
   133  		t.Fatalf("GetCellInfo(non-existing cell) failed: %v", err)
   134  	}
   135  }
   136  
   137  func TestExpandCells(t *testing.T) {
   138  	ctx := context.Background()
   139  	var cells []string
   140  	var err error
   141  	var allCells = "cell1,cell2,cell3"
   142  	type testCase struct {
   143  		name      string
   144  		cellsIn   string
   145  		cellsOut  []string
   146  		errString string
   147  	}
   148  
   149  	testCases := []testCase{
   150  		{"single", "cell1", []string{"cell1"}, ""},
   151  		{"multiple", "cell1,cell2,cell3", []string{"cell1", "cell2", "cell3"}, ""},
   152  		{"empty", "", []string{"cell1", "cell2", "cell3"}, ""},
   153  		{"bad", "unknown", nil, "node doesn't exist"},
   154  	}
   155  
   156  	for _, tCase := range testCases {
   157  		t.Run(tCase.name, func(t *testing.T) {
   158  			cellsIn := tCase.cellsIn
   159  			if cellsIn == "" {
   160  				cellsIn = allCells
   161  			}
   162  			topoCells := strings.Split(cellsIn, ",")
   163  			var ts *topo.Server
   164  			if tCase.name == "bad" {
   165  				ts = memorytopo.NewServer()
   166  			} else {
   167  				ts = memorytopo.NewServer(topoCells...)
   168  			}
   169  			cells, err = ts.ExpandCells(ctx, cellsIn)
   170  			if tCase.errString != "" {
   171  				require.Error(t, err)
   172  				require.Contains(t, err.Error(), tCase.errString)
   173  			} else {
   174  				require.NoError(t, err)
   175  			}
   176  			require.EqualValues(t, tCase.cellsOut, cells)
   177  		})
   178  	}
   179  
   180  	t.Run("aliases", func(t *testing.T) {
   181  		cells := []string{"cell1", "cell2", "cell3"}
   182  		ts := memorytopo.NewServer(cells...)
   183  		err := ts.CreateCellsAlias(ctx, "alias", &topodatapb.CellsAlias{Cells: cells})
   184  		require.NoError(t, err)
   185  
   186  		tests := []struct {
   187  			name      string
   188  			in        string
   189  			out       []string
   190  			shouldErr bool
   191  		}{
   192  			{
   193  				name: "alias only",
   194  				in:   "alias",
   195  				out:  []string{"cell1", "cell2", "cell3"},
   196  			},
   197  			{
   198  				name: "alias and cell in alias", // test deduping logic
   199  				in:   "alias,cell1",
   200  				out:  []string{"cell1", "cell2", "cell3"},
   201  			},
   202  			{
   203  				name: "just cells",
   204  				in:   "cell1",
   205  				out:  []string{"cell1"},
   206  			},
   207  			{
   208  				name:      "missing alias",
   209  				in:        "not_an_alias",
   210  				shouldErr: true,
   211  			},
   212  		}
   213  
   214  		for _, tt := range tests {
   215  			tt := tt
   216  			t.Run(tt.name, func(t *testing.T) {
   217  				expanded, err := ts.ExpandCells(ctx, tt.in)
   218  				if tt.shouldErr {
   219  					assert.Error(t, err)
   220  					return
   221  				}
   222  
   223  				require.NoError(t, err)
   224  				assert.ElementsMatch(t, expanded, tt.out)
   225  			})
   226  		}
   227  	})
   228  }
   229  
   230  func TestDeleteCellInfo(t *testing.T) {
   231  	ctx := context.Background()
   232  	ts := memorytopo.NewServer("zone1", "unreachable")
   233  
   234  	err := ts.UpdateCellInfoFields(ctx, "unreachable", func(ci *topodatapb.CellInfo) error {
   235  		ci.ServerAddress = memorytopo.UnreachableServerAddr
   236  		return nil
   237  	})
   238  	require.NoError(t, err, "failed to update cell to point at unreachable addr")
   239  
   240  	tests := []struct {
   241  		force       bool
   242  		shouldErr   bool
   243  		shouldExist bool
   244  	}{
   245  		{
   246  			force:       false,
   247  			shouldErr:   true,
   248  			shouldExist: true,
   249  		},
   250  		{
   251  			force:       true,
   252  			shouldErr:   false,
   253  			shouldExist: false,
   254  		},
   255  	}
   256  	for _, tt := range tests {
   257  		func() {
   258  			ctx, cancel := context.WithTimeout(ctx, 10*time.Millisecond)
   259  			defer cancel()
   260  
   261  			err := ts.DeleteCellInfo(ctx, "unreachable", tt.force)
   262  			if tt.shouldErr {
   263  				assert.Error(t, err, "force=%t", tt.force)
   264  			} else {
   265  				assert.NoError(t, err, "force=%t", tt.force)
   266  			}
   267  
   268  			ci, err := ts.GetCellInfo(ctx, "unreachable", true /* strongRead */)
   269  			if tt.shouldExist {
   270  				assert.NoError(t, err)
   271  				assert.NotNil(t, ci)
   272  			} else {
   273  				assert.True(t, topo.IsErrType(err, topo.NoNode), "expected cell %q to not exist", "unreachable")
   274  			}
   275  		}()
   276  	}
   277  }