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)