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 }