vitess.io/vitess@v0.16.2/go/vt/topo/topotests/wildcards_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 "testing" 22 23 "vitess.io/vitess/go/vt/topo" 24 "vitess.io/vitess/go/vt/topo/memorytopo" 25 26 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 27 ) 28 29 type topoLayout struct { 30 keyspaces []string 31 shards map[string][]string 32 } 33 34 func (l *topoLayout) initTopo(t *testing.T, ts *topo.Server) { 35 ctx := context.Background() 36 for _, keyspace := range l.keyspaces { 37 if err := ts.CreateKeyspace(ctx, keyspace, &topodatapb.Keyspace{}); err != nil { 38 t.Fatalf("CreateKeyspace(%v) failed: %v", keyspace, err) 39 } 40 } 41 42 for keyspace, shards := range l.shards { 43 for _, shard := range shards { 44 if err := ts.CreateShard(ctx, keyspace, shard); err != nil { 45 t.Fatalf("CreateShard(%v, %v) failed: %v", keyspace, shard, err) 46 } 47 } 48 } 49 } 50 51 func validateKeyspaceWildcard(t *testing.T, l *topoLayout, param string, expected []string) { 52 ts := memorytopo.NewServer() 53 l.initTopo(t, ts) 54 55 ctx := context.Background() 56 r, err := ts.ResolveKeyspaceWildcard(ctx, param) 57 if err != nil { 58 if expected != nil { 59 t.Errorf("was not expecting an error but got: %v", err) 60 } 61 return 62 } 63 64 if len(r) != len(expected) { 65 t.Errorf("got wrong result: %v", r) 66 return 67 } 68 for i, e := range expected { 69 if r[i] != e { 70 t.Errorf("got wrong result[%v]: %v", i, r) 71 } 72 } 73 } 74 75 func TestResolveKeyspaceWildcard(t *testing.T) { 76 l := &topoLayout{ 77 keyspaces: []string{"aaaaa", "aabbb", "bbbbb"}, 78 } 79 validateKeyspaceWildcard(t, l, "*", []string{"aaaaa", "aabbb", "bbbbb"}) 80 validateKeyspaceWildcard(t, l, "aa*", []string{"aaaaa", "aabbb"}) 81 validateKeyspaceWildcard(t, l, "??b??", []string{"aabbb", "bbbbb"}) 82 validateKeyspaceWildcard(t, l, "ccc", []string{"ccc"}) 83 84 validateKeyspaceWildcard(t, l, "ccc\\", nil) 85 } 86 87 func validateShardWildcard(t *testing.T, l *topoLayout, param string, expected []topo.KeyspaceShard) { 88 ts := memorytopo.NewServer() 89 l.initTopo(t, ts) 90 91 ctx := context.Background() 92 r, err := ts.ResolveShardWildcard(ctx, param) 93 if err != nil { 94 if expected != nil { 95 t.Errorf("was not expecting an error but got: %v", err) 96 } 97 return 98 } 99 100 if len(r) != len(expected) { 101 t.Errorf("got wrong result: %v", r) 102 return 103 } 104 for i, e := range expected { 105 if r[i] != e { 106 t.Errorf("got wrong result[%v]: %v", i, r) 107 } 108 } 109 } 110 111 func TestResolveShardWildcard(t *testing.T) { 112 l := &topoLayout{ 113 keyspaces: []string{"aaaaa", "bbbbb"}, 114 shards: map[string][]string{ 115 "aaaaa": {"s0", "s1"}, 116 "bbbbb": {"-40", "40-80", "80-c0", "c0-"}, 117 }, 118 } 119 validateShardWildcard(t, l, "*/*", []topo.KeyspaceShard{ 120 {Keyspace: "aaaaa", Shard: "s0"}, 121 {Keyspace: "aaaaa", Shard: "s1"}, 122 {Keyspace: "bbbbb", Shard: "-40"}, 123 {Keyspace: "bbbbb", Shard: "40-80"}, 124 {Keyspace: "bbbbb", Shard: "80-c0"}, 125 {Keyspace: "bbbbb", Shard: "c0-"}, 126 }) 127 validateShardWildcard(t, l, "aaaaa/*", []topo.KeyspaceShard{ 128 {Keyspace: "aaaaa", Shard: "s0"}, 129 {Keyspace: "aaaaa", Shard: "s1"}, 130 }) 131 validateShardWildcard(t, l, "*/s1", []topo.KeyspaceShard{ 132 {Keyspace: "aaaaa", Shard: "s1"}, 133 }) 134 validateShardWildcard(t, l, "*/*0*", []topo.KeyspaceShard{ 135 {Keyspace: "aaaaa", Shard: "s0"}, 136 {Keyspace: "bbbbb", Shard: "-40"}, 137 {Keyspace: "bbbbb", Shard: "40-80"}, 138 {Keyspace: "bbbbb", Shard: "80-c0"}, 139 {Keyspace: "bbbbb", Shard: "c0-"}, 140 }) 141 validateShardWildcard(t, l, "aaaaa/ccccc", []topo.KeyspaceShard{ 142 {Keyspace: "aaaaa", Shard: "ccccc"}, 143 }) 144 validateShardWildcard(t, l, "ccccc/s0", []topo.KeyspaceShard{ 145 {Keyspace: "ccccc", Shard: "s0"}, 146 }) 147 validateShardWildcard(t, l, "bbbbb/C0-", []topo.KeyspaceShard{ 148 {Keyspace: "bbbbb", Shard: "c0-"}, 149 }) 150 151 // error cases 152 l = &topoLayout{ 153 keyspaces: []string{"aaaaa", "bbbbb"}, 154 shards: map[string][]string{ 155 "aaaaa": nil, 156 }, 157 } 158 159 // these two will return an error as GetShardNames("aaaaa") 160 // will return an error. 161 validateShardWildcard(t, l, "aaaaa/bbbb*", nil) 162 validateShardWildcard(t, l, "aaaa*/bbbb*", nil) 163 164 // GetShardNames("bbbbb") will return ErrNoNode, so we get empty lists 165 // in this case, as the keyspace is a wildcard. 166 validateShardWildcard(t, l, "bbbb*/cccc*", []topo.KeyspaceShard{}) 167 168 // GetShardNames("bbbbb") returns ErrNoNode, so we get an error 169 // in this case, as keyspace is not a wildcard. 170 validateShardWildcard(t, l, "bbbbb/cccc*", nil) 171 172 // GetKeyspaces() will fail hard in this one, so we get an error 173 l = &topoLayout{} 174 validateShardWildcard(t, l, "*/s1", nil) 175 176 // GetKeyspaces() will return an empty list, so no error, no result 177 l = &topoLayout{ 178 keyspaces: []string{}, 179 } 180 validateShardWildcard(t, l, "*/s1", []topo.KeyspaceShard{}) 181 } 182 183 func validateWildcards(t *testing.T, l *topoLayout, param string, expected []string) { 184 ts := memorytopo.NewServer() 185 l.initTopo(t, ts) 186 187 ctx := context.Background() 188 r, err := ts.ResolveWildcards(ctx, topo.GlobalCell, []string{param}) 189 if err != nil { 190 if expected != nil { 191 t.Errorf("was not expecting an error but got: %v", err) 192 } 193 return 194 } 195 196 if len(r) != len(expected) { 197 t.Errorf("got wrong result: %v\nexpected: %v", r, expected) 198 return 199 } 200 for i, e := range expected { 201 if r[i] != e { 202 t.Errorf("got wrong result[%v]: %v", i, r) 203 } 204 } 205 } 206 207 func TestResolveWildcards(t *testing.T) { 208 l := &topoLayout{ 209 keyspaces: []string{"aaaaa", "bbbbb"}, 210 shards: map[string][]string{ 211 "aaaaa": {"s0", "s1"}, 212 "bbbbb": {"-40", "40-80", "80-c0", "c0-"}, 213 }, 214 } 215 // The end path is a wildcard. 216 validateWildcards(t, l, "/keyspaces/*", []string{ 217 "/keyspaces/aaaaa", 218 "/keyspaces/bbbbb", 219 }) 220 // The end path is a directory. 221 validateWildcards(t, l, "/keyspaces/*/shards", []string{ 222 "/keyspaces/aaaaa/shards", 223 "/keyspaces/bbbbb/shards", 224 }) 225 // The end path is a file. 226 validateWildcards(t, l, "/keyspaces/*/Keyspace", []string{ 227 "/keyspaces/aaaaa/Keyspace", 228 "/keyspaces/bbbbb/Keyspace", 229 }) 230 // Double wildcards. 231 validateWildcards(t, l, "/keyspaces/*/shards/*", []string{ 232 "/keyspaces/aaaaa/shards/s0", 233 "/keyspaces/aaaaa/shards/s1", 234 "/keyspaces/bbbbb/shards/-40", 235 "/keyspaces/bbbbb/shards/40-80", 236 "/keyspaces/bbbbb/shards/80-c0", 237 "/keyspaces/bbbbb/shards/c0-", 238 }) 239 // Double wildcards, subset of matches. 240 validateWildcards(t, l, "/keyspaces/*/shards/s*", []string{ 241 "/keyspaces/aaaaa/shards/s0", 242 "/keyspaces/aaaaa/shards/s1", 243 }) 244 }