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 }