vitess.io/vitess@v0.16.2/go/vt/vtgate/endtoend/update/lookup_unique_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 endtoend
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"os"
    23  	"testing"
    24  
    25  	"github.com/stretchr/testify/require"
    26  
    27  	"vitess.io/vitess/go/internal/flag"
    28  	"vitess.io/vitess/go/mysql"
    29  	"vitess.io/vitess/go/test/endtoend/utils"
    30  	"vitess.io/vitess/go/vt/log"
    31  	"vitess.io/vitess/go/vt/vttest"
    32  
    33  	vschemapb "vitess.io/vitess/go/vt/proto/vschema"
    34  	vttestpb "vitess.io/vitess/go/vt/proto/vttest"
    35  )
    36  
    37  var (
    38  	cluster     *vttest.LocalCluster
    39  	vtParams    mysql.ConnParams
    40  	mysqlParams mysql.ConnParams
    41  	grpcAddress string
    42  
    43  	schema = `
    44  create table t1(
    45  	id bigint,
    46  	sharding_key bigint,
    47  	primary key(id)
    48  ) Engine=InnoDB;
    49  
    50  create table t1_id_idx(
    51  	id bigint,
    52  	keyspace_id varbinary(10),
    53  	primary key(id)
    54  ) Engine=InnoDB;
    55  
    56  create table t2(
    57  	id bigint,
    58  	t1_id bigint,
    59  	sharding_key bigint,
    60  	primary key(id)
    61  ) Engine=InnoDB;
    62  
    63  create table t2_id_idx(
    64  	id bigint,
    65  	keyspace_id varbinary(10),
    66  	primary key(id)
    67  ) Engine=InnoDB;
    68  `
    69  
    70  	vschema = &vschemapb.Keyspace{
    71  		Sharded: true,
    72  		Vindexes: map[string]*vschemapb.Vindex{
    73  			"hash": {
    74  				Type: "hash",
    75  			},
    76  			"t1_id_idx": {
    77  				Type: "consistent_lookup_unique",
    78  				Params: map[string]string{
    79  					"table": "t1_id_idx",
    80  					"from":  "id",
    81  					"to":    "keyspace_id",
    82  				},
    83  				Owner: "t1",
    84  			},
    85  			"t2_id_idx": {
    86  				Type: "consistent_lookup_unique",
    87  				Params: map[string]string{
    88  					"table": "t2_id_idx",
    89  					"from":  "id",
    90  					"to":    "keyspace_id",
    91  				},
    92  				Owner: "t2",
    93  			},
    94  		},
    95  		Tables: map[string]*vschemapb.Table{
    96  			"t1": {
    97  				ColumnVindexes: []*vschemapb.ColumnVindex{{
    98  					Column: "sharding_key",
    99  					Name:   "hash",
   100  				}, {
   101  					Column: "id",
   102  					Name:   "t1_id_idx",
   103  				}},
   104  			},
   105  			"t1_id_idx": {
   106  				ColumnVindexes: []*vschemapb.ColumnVindex{{
   107  					Column: "id",
   108  					Name:   "hash",
   109  				}},
   110  			},
   111  			"t2": {
   112  				ColumnVindexes: []*vschemapb.ColumnVindex{{
   113  					Column: "sharding_key",
   114  					Name:   "hash",
   115  				}, {
   116  					Column: "t1_id",
   117  					Name:   "t1_id_idx",
   118  				}, {
   119  					Column: "id",
   120  					Name:   "t2_id_idx",
   121  				}},
   122  			},
   123  			"t2_id_idx": {
   124  				ColumnVindexes: []*vschemapb.ColumnVindex{{
   125  					Column: "id",
   126  					Name:   "hash",
   127  				}},
   128  			},
   129  		},
   130  	}
   131  )
   132  
   133  func TestMain(m *testing.M) {
   134  	flag.ParseFlagsForTest()
   135  
   136  	exitCode := func() int {
   137  		var cfg vttest.Config
   138  		cfg.Topology = &vttestpb.VTTestTopology{
   139  			Keyspaces: []*vttestpb.Keyspace{{
   140  				Name: "ks",
   141  				Shards: []*vttestpb.Shard{{
   142  					Name: "-80",
   143  				}, {
   144  					Name: "80-",
   145  				}},
   146  			}},
   147  		}
   148  		if err := cfg.InitSchemas("ks", schema, vschema); err != nil {
   149  			fmt.Fprintf(os.Stderr, "%v\n", err)
   150  			os.RemoveAll(cfg.SchemaDir)
   151  			return 1
   152  		}
   153  		defer os.RemoveAll(cfg.SchemaDir)
   154  
   155  		cluster = &vttest.LocalCluster{
   156  			Config: cfg,
   157  		}
   158  		if err := cluster.Setup(); err != nil {
   159  			fmt.Fprintf(os.Stderr, "%v\n", err)
   160  			//log error
   161  			if err := cluster.TearDown(); err != nil {
   162  				log.Errorf("cluster.TearDown() did not work: ", err)
   163  			}
   164  			return 1
   165  		}
   166  		defer cluster.TearDown()
   167  
   168  		vtParams = mysql.ConnParams{
   169  			Host: "localhost",
   170  			Port: cluster.Env.PortForProtocol("vtcombo_mysql_port", ""),
   171  		}
   172  		mysqlParams = cluster.MySQLConnParams()
   173  		grpcAddress = fmt.Sprintf("localhost:%d", cluster.Env.PortForProtocol("vtcombo", "grpc"))
   174  
   175  		return m.Run()
   176  	}()
   177  	os.Exit(exitCode)
   178  }
   179  
   180  func TestUpdateUnownedLookupVindexValidValue(t *testing.T) {
   181  	ctx := context.Background()
   182  	conn, err := mysql.Connect(ctx, &vtParams)
   183  
   184  	if err != nil {
   185  		t.Fatal(err)
   186  	}
   187  	t.Cleanup(func() { conn.Close() })
   188  
   189  	utils.Exec(t, conn, "insert into t1(id, sharding_key) values(1,1), (2,1), (3,2), (4,2)")
   190  	t.Cleanup(func() { utils.Exec(t, conn, "delete from t1") })
   191  
   192  	utils.Exec(t, conn, "insert into t2(id, sharding_key, t1_id) values (1,1,1), (2,1,2), (3,2,3), (4,2,4)")
   193  	t.Cleanup(func() { utils.Exec(t, conn, "delete from t2") })
   194  
   195  	utils.Exec(t, conn, "UPDATE t2 SET t1_id = 1 WHERE id = 2")
   196  
   197  	qr := utils.Exec(t, conn, "select id, sharding_key, t1_id from t2 WHERE id = 2")
   198  	if got, want := fmt.Sprintf("%v", qr.Rows), `[[INT64(2) INT64(1) INT64(1)]]`; got != want {
   199  		t.Errorf("select:\n%v want\n%v", got, want)
   200  	}
   201  }
   202  
   203  func TestUpdateUnownedLookupVindexInvalidValue(t *testing.T) {
   204  	ctx := context.Background()
   205  	conn, err := mysql.Connect(ctx, &vtParams)
   206  
   207  	if err != nil {
   208  		t.Fatal(err)
   209  	}
   210  	t.Cleanup(func() { conn.Close() })
   211  
   212  	utils.Exec(t, conn, "insert into t1(id, sharding_key) values(1,1), (2,1), (3,2), (4,2)")
   213  	t.Cleanup(func() { utils.Exec(t, conn, "delete from t1") })
   214  
   215  	utils.Exec(t, conn, "insert into t2(id, sharding_key, t1_id) values (1,1,1), (2,1,2), (3,2,3), (4,2,4)")
   216  	t.Cleanup(func() { utils.Exec(t, conn, "delete from t2") })
   217  
   218  	_, err = conn.ExecuteFetch("UPDATE t2 SET t1_id = 5 WHERE id = 2", 1000, true)
   219  	require.EqualError(t, err, `values [INT64(5)] for column [t1_id] does not map to keyspace ids (errno 1105) (sqlstate HY000) during query: UPDATE t2 SET t1_id = 5 WHERE id = 2`)
   220  
   221  	qr := utils.Exec(t, conn, "select id, sharding_key, t1_id from t2 WHERE id = 2")
   222  	if got, want := fmt.Sprintf("%v", qr.Rows), `[[INT64(2) INT64(1) INT64(2)]]`; got != want {
   223  		t.Errorf("select:\n%v want\n%v", got, want)
   224  	}
   225  }
   226  
   227  func TestUpdateUnownedLookupVindexToNull(t *testing.T) {
   228  	ctx := context.Background()
   229  	conn, err := mysql.Connect(ctx, &vtParams)
   230  	if err != nil {
   231  		t.Fatal(err)
   232  	}
   233  	t.Cleanup(func() { conn.Close() })
   234  
   235  	utils.Exec(t, conn, "insert into t1(id, sharding_key) values(1,1), (2,1), (3,2), (4,2)")
   236  	t.Cleanup(func() { utils.Exec(t, conn, "delete from t1") })
   237  
   238  	utils.Exec(t, conn, "insert into t2(id, sharding_key, t1_id) values (1,1,1), (2,1,2), (3,2,3), (4,2,4)")
   239  	t.Cleanup(func() { utils.Exec(t, conn, "delete from t2") })
   240  
   241  	utils.Exec(t, conn, "UPDATE t2 SET t1_id = NULL WHERE id = 2")
   242  
   243  	qr := utils.Exec(t, conn, "select id, sharding_key, t1_id from t2 WHERE id = 2")
   244  	if got, want := fmt.Sprintf("%v", qr.Rows), `[[INT64(2) INT64(1) NULL]]`; got != want {
   245  		t.Errorf("select:\n%v want\n%v", got, want)
   246  	}
   247  }