vitess.io/vitess@v0.16.2/go/vt/vtgate/vschema_manager_test.go (about) 1 package vtgate 2 3 import ( 4 "testing" 5 6 "vitess.io/vitess/go/test/utils" 7 querypb "vitess.io/vitess/go/vt/proto/query" 8 "vitess.io/vitess/go/vt/sqlparser" 9 10 vschemapb "vitess.io/vitess/go/vt/proto/vschema" 11 "vitess.io/vitess/go/vt/vtgate/vindexes" 12 ) 13 14 func TestVSchemaUpdate(t *testing.T) { 15 cols1 := []vindexes.Column{{ 16 Name: sqlparser.NewIdentifierCI("id"), 17 Type: querypb.Type_INT64, 18 }} 19 cols2 := []vindexes.Column{{ 20 Name: sqlparser.NewIdentifierCI("uid"), 21 Type: querypb.Type_INT64, 22 }, { 23 Name: sqlparser.NewIdentifierCI("name"), 24 Type: querypb.Type_VARCHAR, 25 }} 26 ks := &vindexes.Keyspace{Name: "ks"} 27 dual := &vindexes.Table{Type: vindexes.TypeReference, Name: sqlparser.NewIdentifierCS("dual"), Keyspace: ks} 28 tblNoCol := &vindexes.Table{Name: sqlparser.NewIdentifierCS("tbl"), Keyspace: ks, ColumnListAuthoritative: true} 29 tblCol1 := &vindexes.Table{Name: sqlparser.NewIdentifierCS("tbl"), Keyspace: ks, Columns: cols1, ColumnListAuthoritative: true} 30 tblCol2 := &vindexes.Table{Name: sqlparser.NewIdentifierCS("tbl"), Keyspace: ks, Columns: cols2, ColumnListAuthoritative: true} 31 tblCol2NA := &vindexes.Table{Name: sqlparser.NewIdentifierCS("tbl"), Keyspace: ks, Columns: cols2} 32 33 tcases := []struct { 34 name string 35 srvVschema *vschemapb.SrvVSchema 36 currentVSchema *vindexes.VSchema 37 schema map[string][]vindexes.Column 38 expected *vindexes.VSchema 39 }{{ 40 name: "0 Schematracking- 1 srvVSchema", 41 srvVschema: makeTestSrvVSchema("ks", false, map[string]*vschemapb.Table{ 42 "tbl": { 43 Columns: []*vschemapb.Column{{Name: "uid", Type: querypb.Type_INT64}, {Name: "name", Type: querypb.Type_VARCHAR}}, 44 ColumnListAuthoritative: false, 45 }, 46 }), 47 expected: makeTestVSchema("ks", false, map[string]*vindexes.Table{"dual": dual, "tbl": tblCol2NA}), 48 }, { 49 name: "1 Schematracking- 0 srvVSchema", 50 srvVschema: makeTestSrvVSchema("ks", false, nil), 51 schema: map[string][]vindexes.Column{"tbl": cols1}, 52 expected: makeTestVSchema("ks", false, map[string]*vindexes.Table{"dual": dual, "tbl": tblCol1}), 53 }, { 54 name: "1 Schematracking - 1 srvVSchema (no columns) not authoritative", 55 srvVschema: makeTestSrvVSchema("ks", false, map[string]*vschemapb.Table{"tbl": {}}), 56 schema: map[string][]vindexes.Column{"tbl": cols1}, 57 // schema will override what srvSchema has. 58 expected: makeTestVSchema("ks", false, map[string]*vindexes.Table{"dual": dual, "tbl": tblCol1}), 59 }, { 60 name: "1 Schematracking - 1 srvVSchema (have columns) not authoritative", 61 srvVschema: makeTestSrvVSchema("ks", false, map[string]*vschemapb.Table{ 62 "tbl": { 63 Columns: []*vschemapb.Column{{Name: "uid", Type: querypb.Type_INT64}, {Name: "name", Type: querypb.Type_VARCHAR}}, 64 ColumnListAuthoritative: false, 65 }, 66 }), 67 schema: map[string][]vindexes.Column{"tbl": cols1}, 68 // schema will override what srvSchema has. 69 expected: makeTestVSchema("ks", false, map[string]*vindexes.Table{"dual": dual, "tbl": tblCol1}), 70 }, { 71 name: "1 Schematracking - 1 srvVSchema (no columns) authoritative", 72 srvVschema: makeTestSrvVSchema("ks", false, map[string]*vschemapb.Table{"tbl": { 73 ColumnListAuthoritative: true, 74 }}), 75 schema: map[string][]vindexes.Column{"tbl": cols1}, 76 // schema will override what srvSchema has. 77 expected: makeTestVSchema("ks", false, map[string]*vindexes.Table{"dual": dual, "tbl": tblNoCol}), 78 }, { 79 name: "1 Schematracking - 1 srvVSchema (have columns) authoritative", 80 srvVschema: makeTestSrvVSchema("ks", false, map[string]*vschemapb.Table{ 81 "tbl": { 82 Columns: []*vschemapb.Column{{Name: "uid", Type: querypb.Type_INT64}, {Name: "name", Type: querypb.Type_VARCHAR}}, 83 ColumnListAuthoritative: true, 84 }, 85 }), 86 schema: map[string][]vindexes.Column{"tbl": cols1}, 87 // schema tracker will be ignored for authoritative tables. 88 expected: makeTestVSchema("ks", false, map[string]*vindexes.Table{"dual": dual, "tbl": tblCol2}), 89 }, { 90 name: "srvVschema received as nil", 91 schema: map[string][]vindexes.Column{"tbl": cols1}, 92 expected: makeTestEmptyVSchema(), 93 }, { 94 name: "srvVschema received as nil - have existing vschema", 95 currentVSchema: &vindexes.VSchema{}, 96 schema: map[string][]vindexes.Column{"tbl": cols1}, 97 expected: &vindexes.VSchema{}, 98 }} 99 100 vm := &VSchemaManager{} 101 var vs *vindexes.VSchema 102 vm.subscriber = func(vschema *vindexes.VSchema, _ *VSchemaStats) { 103 vs = vschema 104 } 105 for _, tcase := range tcases { 106 t.Run(tcase.name, func(t *testing.T) { 107 vs = nil 108 vm.schema = &fakeSchema{t: tcase.schema} 109 vm.currentSrvVschema = nil 110 vm.currentVschema = tcase.currentVSchema 111 vm.VSchemaUpdate(tcase.srvVschema, nil) 112 113 utils.MustMatchFn(".globalTables", ".uniqueVindexes")(t, tcase.expected, vs) 114 if tcase.srvVschema != nil { 115 utils.MustMatch(t, vs, vm.currentVschema, "currentVschema should have same reference as Vschema") 116 } 117 }) 118 } 119 } 120 121 func TestRebuildVSchema(t *testing.T) { 122 cols1 := []vindexes.Column{{ 123 Name: sqlparser.NewIdentifierCI("id"), 124 Type: querypb.Type_INT64, 125 }} 126 cols2 := []vindexes.Column{{ 127 Name: sqlparser.NewIdentifierCI("uid"), 128 Type: querypb.Type_INT64, 129 }, { 130 Name: sqlparser.NewIdentifierCI("name"), 131 Type: querypb.Type_VARCHAR, 132 }} 133 ks := &vindexes.Keyspace{Name: "ks"} 134 dual := &vindexes.Table{Type: vindexes.TypeReference, Name: sqlparser.NewIdentifierCS("dual"), Keyspace: ks} 135 tblNoCol := &vindexes.Table{Name: sqlparser.NewIdentifierCS("tbl"), Keyspace: ks, ColumnListAuthoritative: true} 136 tblCol1 := &vindexes.Table{Name: sqlparser.NewIdentifierCS("tbl"), Keyspace: ks, Columns: cols1, ColumnListAuthoritative: true} 137 tblCol2 := &vindexes.Table{Name: sqlparser.NewIdentifierCS("tbl"), Keyspace: ks, Columns: cols2, ColumnListAuthoritative: true} 138 tblCol2NA := &vindexes.Table{Name: sqlparser.NewIdentifierCS("tbl"), Keyspace: ks, Columns: cols2} 139 140 tcases := []struct { 141 name string 142 srvVschema *vschemapb.SrvVSchema 143 schema map[string][]vindexes.Column 144 expected *vindexes.VSchema 145 }{{ 146 name: "0 Schematracking- 1 srvVSchema", 147 srvVschema: makeTestSrvVSchema("ks", false, map[string]*vschemapb.Table{ 148 "tbl": { 149 Columns: []*vschemapb.Column{{Name: "uid", Type: querypb.Type_INT64}, {Name: "name", Type: querypb.Type_VARCHAR}}, 150 ColumnListAuthoritative: false, 151 }, 152 }), 153 expected: makeTestVSchema("ks", false, map[string]*vindexes.Table{"dual": dual, "tbl": tblCol2NA}), 154 }, { 155 name: "1 Schematracking- 0 srvVSchema", 156 srvVschema: makeTestSrvVSchema("ks", false, nil), 157 schema: map[string][]vindexes.Column{"tbl": cols1}, 158 expected: makeTestVSchema("ks", false, map[string]*vindexes.Table{"dual": dual, "tbl": tblCol1}), 159 }, { 160 name: "1 Schematracking - 1 srvVSchema (no columns) not authoritative", 161 srvVschema: makeTestSrvVSchema("ks", false, map[string]*vschemapb.Table{"tbl": {}}), 162 schema: map[string][]vindexes.Column{"tbl": cols1}, 163 // schema will override what srvSchema has. 164 expected: makeTestVSchema("ks", false, map[string]*vindexes.Table{"dual": dual, "tbl": tblCol1}), 165 }, { 166 name: "1 Schematracking - 1 srvVSchema (have columns) not authoritative", 167 srvVschema: makeTestSrvVSchema("ks", false, map[string]*vschemapb.Table{ 168 "tbl": { 169 Columns: []*vschemapb.Column{{Name: "uid", Type: querypb.Type_INT64}, {Name: "name", Type: querypb.Type_VARCHAR}}, 170 ColumnListAuthoritative: false, 171 }, 172 }), 173 schema: map[string][]vindexes.Column{"tbl": cols1}, 174 // schema will override what srvSchema has. 175 expected: makeTestVSchema("ks", false, map[string]*vindexes.Table{"dual": dual, "tbl": tblCol1}), 176 }, { 177 name: "1 Schematracking - 1 srvVSchema (no columns) authoritative", 178 srvVschema: makeTestSrvVSchema("ks", false, map[string]*vschemapb.Table{"tbl": { 179 ColumnListAuthoritative: true, 180 }}), 181 schema: map[string][]vindexes.Column{"tbl": cols1}, 182 // schema will override what srvSchema has. 183 expected: makeTestVSchema("ks", false, map[string]*vindexes.Table{"dual": dual, "tbl": tblNoCol}), 184 }, { 185 name: "1 Schematracking - 1 srvVSchema (have columns) authoritative", 186 srvVschema: makeTestSrvVSchema("ks", false, map[string]*vschemapb.Table{ 187 "tbl": { 188 Columns: []*vschemapb.Column{{Name: "uid", Type: querypb.Type_INT64}, {Name: "name", Type: querypb.Type_VARCHAR}}, 189 ColumnListAuthoritative: true, 190 }, 191 }), 192 schema: map[string][]vindexes.Column{"tbl": cols1}, 193 // schema tracker will be ignored for authoritative tables. 194 expected: makeTestVSchema("ks", false, map[string]*vindexes.Table{"dual": dual, "tbl": tblCol2}), 195 }, { 196 name: "srvVschema received as nil", 197 schema: map[string][]vindexes.Column{"tbl": cols1}, 198 }} 199 200 vm := &VSchemaManager{} 201 var vs *vindexes.VSchema 202 vm.subscriber = func(vschema *vindexes.VSchema, _ *VSchemaStats) { 203 vs = vschema 204 } 205 for _, tcase := range tcases { 206 t.Run(tcase.name, func(t *testing.T) { 207 vs = nil 208 vm.schema = &fakeSchema{t: tcase.schema} 209 vm.currentSrvVschema = tcase.srvVschema 210 vm.currentVschema = nil 211 vm.Rebuild() 212 213 utils.MustMatchFn(".globalTables", ".uniqueVindexes")(t, tcase.expected, vs) 214 if vs != nil { 215 utils.MustMatch(t, vs, vm.currentVschema, "currentVschema should have same reference as Vschema") 216 } 217 }) 218 } 219 } 220 221 func makeTestVSchema(ks string, sharded bool, tbls map[string]*vindexes.Table) *vindexes.VSchema { 222 keyspaceSchema := &vindexes.KeyspaceSchema{ 223 Keyspace: &vindexes.Keyspace{ 224 Name: ks, 225 Sharded: sharded, 226 }, 227 Tables: tbls, 228 Vindexes: map[string]vindexes.Vindex{}, 229 } 230 vs := makeTestEmptyVSchema() 231 vs.Keyspaces[ks] = keyspaceSchema 232 return vs 233 } 234 235 func makeTestEmptyVSchema() *vindexes.VSchema { 236 return &vindexes.VSchema{ 237 RoutingRules: map[string]*vindexes.RoutingRule{}, 238 Keyspaces: map[string]*vindexes.KeyspaceSchema{}, 239 } 240 } 241 242 func makeTestSrvVSchema(ks string, sharded bool, tbls map[string]*vschemapb.Table) *vschemapb.SrvVSchema { 243 keyspaceSchema := &vschemapb.Keyspace{ 244 Sharded: sharded, 245 Tables: tbls, 246 } 247 return &vschemapb.SrvVSchema{ 248 Keyspaces: map[string]*vschemapb.Keyspace{ks: keyspaceSchema}, 249 } 250 } 251 252 type fakeSchema struct { 253 t map[string][]vindexes.Column 254 } 255 256 func (f *fakeSchema) Tables(string) map[string][]vindexes.Column { 257 return f.t 258 } 259 260 func (f *fakeSchema) Views(ks string) map[string]sqlparser.SelectStatement { 261 return nil 262 } 263 264 var _ SchemaInfo = (*fakeSchema)(nil)