vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletserver/schema/load_table_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 schema
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"reflect"
    23  	"strings"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/stretchr/testify/assert"
    28  	"github.com/stretchr/testify/require"
    29  
    30  	"vitess.io/vitess/go/mysql/fakesqldb"
    31  	"vitess.io/vitess/go/sqltypes"
    32  	querypb "vitess.io/vitess/go/vt/proto/query"
    33  	"vitess.io/vitess/go/vt/sqlparser"
    34  	"vitess.io/vitess/go/vt/vttablet/tabletserver/connpool"
    35  	"vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv"
    36  )
    37  
    38  func TestLoadTable(t *testing.T) {
    39  	db := fakesqldb.New(t)
    40  	defer db.Close()
    41  	mockLoadTableQueries(db)
    42  	table, err := newTestLoadTable("USER_TABLE", "test table", db)
    43  	if err != nil {
    44  		t.Fatal(err)
    45  	}
    46  	want := &Table{
    47  		Name: sqlparser.NewIdentifierCS("test_table"),
    48  		Fields: []*querypb.Field{{
    49  			Name: "pk",
    50  			Type: sqltypes.Int32,
    51  		}, {
    52  			Name: "name",
    53  			Type: sqltypes.Int32,
    54  		}, {
    55  			Name: "addr",
    56  			Type: sqltypes.Int32,
    57  		}},
    58  	}
    59  	assert.Equal(t, want, table)
    60  }
    61  
    62  func TestLoadTableSequence(t *testing.T) {
    63  	db := fakesqldb.New(t)
    64  	defer db.Close()
    65  	mockLoadTableQueries(db)
    66  	table, err := newTestLoadTable("USER_TABLE", "vitess_sequence", db)
    67  	if err != nil {
    68  		t.Fatal(err)
    69  	}
    70  	want := &Table{
    71  		Name:         sqlparser.NewIdentifierCS("test_table"),
    72  		Type:         Sequence,
    73  		SequenceInfo: &SequenceInfo{},
    74  	}
    75  	table.Fields = nil
    76  	table.PKColumns = nil
    77  	if !reflect.DeepEqual(table, want) {
    78  		t.Errorf("Table:\n%#v, want\n%#v", table, want)
    79  	}
    80  }
    81  
    82  func TestLoadTableMessage(t *testing.T) {
    83  	db := fakesqldb.New(t)
    84  	defer db.Close()
    85  	mockMessageTableQueries(db)
    86  	table, err := newTestLoadTable("USER_TABLE", "vitess_message,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30", db)
    87  	if err != nil {
    88  		t.Fatal(err)
    89  	}
    90  	want := &Table{
    91  		Name: sqlparser.NewIdentifierCS("test_table"),
    92  		Type: Message,
    93  		Fields: []*querypb.Field{{
    94  			Name: "id",
    95  			Type: sqltypes.Int64,
    96  		}, {
    97  			Name: "priority",
    98  			Type: sqltypes.Int64,
    99  		}, {
   100  			Name: "time_next",
   101  			Type: sqltypes.Int64,
   102  		}, {
   103  			Name: "epoch",
   104  			Type: sqltypes.Int64,
   105  		}, {
   106  			Name: "time_acked",
   107  			Type: sqltypes.Int64,
   108  		}, {
   109  			Name: "message",
   110  			Type: sqltypes.VarBinary,
   111  		}},
   112  		MessageInfo: &MessageInfo{
   113  			Fields: []*querypb.Field{{
   114  				Name: "id",
   115  				Type: sqltypes.Int64,
   116  			}, {
   117  				Name: "message",
   118  				Type: sqltypes.VarBinary,
   119  			}},
   120  			AckWaitDuration:    30 * time.Second,
   121  			PurgeAfterDuration: 120 * time.Second,
   122  			MinBackoff:         30 * time.Second,
   123  			BatchSize:          1,
   124  			CacheSize:          10,
   125  			PollInterval:       30 * time.Second,
   126  		},
   127  	}
   128  	assert.Equal(t, want, table)
   129  
   130  	// Test loading min/max backoff
   131  	table, err = newTestLoadTable("USER_TABLE", "vitess_message,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30,vt_min_backoff=10,vt_max_backoff=100", db)
   132  	require.NoError(t, err)
   133  	want.MessageInfo.MinBackoff = 10 * time.Second
   134  	want.MessageInfo.MaxBackoff = 100 * time.Second
   135  	assert.Equal(t, want, table)
   136  
   137  	//
   138  	// multiple tests for vt_message_cols
   139  	//
   140  	origFields := want.MessageInfo.Fields
   141  
   142  	// Test loading id column from vt_message_cols
   143  	table, err = newTestLoadTable("USER_TABLE", "vitess_message,vt_message_cols=id,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30,vt_min_backoff=10,vt_max_backoff=100", db)
   144  	require.NoError(t, err)
   145  	want.MessageInfo.Fields = []*querypb.Field{{
   146  		Name: "id",
   147  		Type: sqltypes.Int64,
   148  	}}
   149  	assert.Equal(t, want, table)
   150  
   151  	// Test loading message column from vt_message_cols
   152  	_, err = newTestLoadTable("USER_TABLE", "vitess_message,vt_message_cols=message,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30,vt_min_backoff=10,vt_max_backoff=100", db)
   153  	require.Equal(t, errors.New("vt_message_cols must begin with id: test_table"), err)
   154  
   155  	// Test loading id & message columns from vt_message_cols
   156  	table, err = newTestLoadTable("USER_TABLE", "vitess_message,vt_message_cols=id|message,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30,vt_min_backoff=10,vt_max_backoff=100", db)
   157  	require.NoError(t, err)
   158  	want.MessageInfo.Fields = []*querypb.Field{{
   159  		Name: "id",
   160  		Type: sqltypes.Int64,
   161  	}, {
   162  		Name: "message",
   163  		Type: sqltypes.VarBinary,
   164  	}}
   165  	assert.Equal(t, want, table)
   166  
   167  	// Test loading id & message columns in reverse order from vt_message_cols
   168  	_, err = newTestLoadTable("USER_TABLE", "vitess_message,vt_message_cols=message|id,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30,vt_min_backoff=10,vt_max_backoff=100", db)
   169  	require.Equal(t, errors.New("vt_message_cols must begin with id: test_table"), err)
   170  
   171  	// Test setting zero columns on vt_message_cols, which is ignored and loads the default columns
   172  	table, err = newTestLoadTable("USER_TABLE", "vitess_message,vt_message_cols,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30,vt_min_backoff=10,vt_max_backoff=100", db)
   173  	require.NoError(t, err)
   174  	want.MessageInfo.Fields = []*querypb.Field{{
   175  		Name: "id",
   176  		Type: sqltypes.Int64,
   177  	}, {
   178  		Name: "message",
   179  		Type: sqltypes.VarBinary,
   180  	}}
   181  	assert.Equal(t, want, table)
   182  
   183  	// reset fields after all vt_message_cols tests
   184  	want.MessageInfo.Fields = origFields
   185  
   186  	//
   187  	// end vt_message_cols tests
   188  	//
   189  
   190  	// Missing property
   191  	_, err = newTestLoadTable("USER_TABLE", "vitess_message,vt_ack_wait=30", db)
   192  	wanterr := "not specified for message table"
   193  	if err == nil || !strings.Contains(err.Error(), wanterr) {
   194  		t.Errorf("newTestLoadTable: %v, want %s", err, wanterr)
   195  	}
   196  
   197  	mockLoadTableQueries(db)
   198  	_, err = newTestLoadTable("USER_TABLE", "vitess_message,vt_ack_wait=30,vt_purge_after=120,vt_batch_size=1,vt_cache_size=10,vt_poller_interval=30", db)
   199  	wanterr = "missing from message table: test_table"
   200  	if err == nil || !strings.Contains(err.Error(), wanterr) {
   201  		t.Errorf("newTestLoadTable: %v, must contain %s", err, wanterr)
   202  	}
   203  }
   204  
   205  func newTestLoadTable(tableType string, comment string, db *fakesqldb.DB) (*Table, error) {
   206  	ctx := context.Background()
   207  	appParams := db.ConnParams()
   208  	dbaParams := db.ConnParams()
   209  	connPool := connpool.NewPool(tabletenv.NewEnv(nil, "SchemaTest"), "", tabletenv.ConnPoolConfig{
   210  		Size:               2,
   211  		IdleTimeoutSeconds: 10,
   212  	})
   213  	connPool.Open(appParams, dbaParams, appParams)
   214  	conn, err := connPool.Get(ctx, nil)
   215  	if err != nil {
   216  		return nil, err
   217  	}
   218  	defer conn.Recycle()
   219  
   220  	return LoadTable(conn, "fakesqldb", "test_table", comment)
   221  }
   222  
   223  func mockLoadTableQueries(db *fakesqldb.DB) {
   224  	db.ClearQueryPattern()
   225  	db.MockQueriesForTable("test_table", &sqltypes.Result{
   226  		Fields: []*querypb.Field{{
   227  			Name: "pk",
   228  			Type: sqltypes.Int32,
   229  		}, {
   230  			Name: "name",
   231  			Type: sqltypes.Int32,
   232  		}, {
   233  			Name: "addr",
   234  			Type: sqltypes.Int32,
   235  		}},
   236  	})
   237  }
   238  
   239  func mockMessageTableQueries(db *fakesqldb.DB) {
   240  	db.ClearQueryPattern()
   241  	db.MockQueriesForTable("test_table", &sqltypes.Result{
   242  		Fields: []*querypb.Field{{
   243  			Name: "id",
   244  			Type: sqltypes.Int64,
   245  		}, {
   246  			Name: "priority",
   247  			Type: sqltypes.Int64,
   248  		}, {
   249  			Name: "time_next",
   250  			Type: sqltypes.Int64,
   251  		}, {
   252  			Name: "epoch",
   253  			Type: sqltypes.Int64,
   254  		}, {
   255  			Name: "time_acked",
   256  			Type: sqltypes.Int64,
   257  		}, {
   258  			Name: "message",
   259  			Type: sqltypes.VarBinary,
   260  		}},
   261  	})
   262  }