Skip to content

Commit 8ab64dc

Browse files
committed
add tests
Signed-off-by: Nick Van Wiggeren <[email protected]>
1 parent 29fb9e0 commit 8ab64dc

File tree

4 files changed

+189
-4
lines changed

4 files changed

+189
-4
lines changed

go/test/endtoend/vtgate/misc_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,73 @@ func TestDDLTargeted(t *testing.T) {
835835
utils.AssertMatches(t, conn, `select id from ddl_targeted`, `[[INT64(1)]]`)
836836
}
837837

838+
// TestTabletTargeting tests tablet-specific routing with USE keyspace@tablet-alias syntax.
839+
// In a sharded keyspace, this validates that tablet-specific routing overrides normal hash-based routing.
840+
func TestTabletTargeting(t *testing.T) {
841+
ctx := context.Background()
842+
conn, err := mysql.Connect(ctx, &vtParams)
843+
require.NoError(t, err)
844+
defer conn.Close()
845+
846+
// Get tablet aliases from show vitess_tablets
847+
qr := utils.Exec(t, conn, "show vitess_tablets")
848+
require.Greater(t, len(qr.Rows), 0, "no tablets found")
849+
850+
// Find PRIMARY tablets for both shards (-80 and 80-)
851+
var primaryShard80Minus string // We'll target this shard
852+
var primaryShard80Plus string // We'll verify this shard gets no writes
853+
for _, row := range qr.Rows {
854+
shard := row[2].ToString()
855+
tabletType := row[3].ToString()
856+
if tabletType == "PRIMARY" {
857+
switch shard {
858+
case "-80":
859+
primaryShard80Minus = row[0].ToString()
860+
case "80-":
861+
primaryShard80Plus = row[0].ToString()
862+
}
863+
}
864+
}
865+
require.NotEmpty(t, primaryShard80Minus, "no PRIMARY tablet found for -80 shard")
866+
require.NotEmpty(t, primaryShard80Plus, "no PRIMARY tablet found for 80- shard")
867+
868+
// Test: Target the -80 shard's PRIMARY and insert rows that normally hash to -80
869+
// id1=1 and id1=2 both hash to -80 shard based on the hash vindex
870+
utils.Exec(t, conn, fmt.Sprintf("USE ks@%s", primaryShard80Minus))
871+
utils.Exec(t, conn, "insert into t1(id1, id2) values(1, 100), (2, 200)")
872+
utils.AssertMatches(t, conn, "select id1 from t1 where id1 in (1, 2) order by id1", "[[INT64(1)] [INT64(2)]]")
873+
874+
// Test: Verify the other shard (80-) did not receive these writes
875+
utils.Exec(t, conn, fmt.Sprintf("USE ks@%s", primaryShard80Plus))
876+
utils.AssertIsEmpty(t, conn, "select id1 from t1 where id1 in (1, 2)")
877+
878+
// Test: Transaction with tablet-specific routing
879+
utils.Exec(t, conn, fmt.Sprintf("USE ks@%s", primaryShard80Minus))
880+
utils.Exec(t, conn, "begin")
881+
utils.Exec(t, conn, "insert into t1(id1, id2) values(10, 300)")
882+
utils.Exec(t, conn, "commit")
883+
utils.AssertMatches(t, conn, "select id1 from t1 where id1=10", "[[INT64(10)]]")
884+
885+
// Test: Verify the other shard still has no data for our test rows
886+
utils.Exec(t, conn, fmt.Sprintf("USE ks@%s", primaryShard80Plus))
887+
utils.AssertIsEmpty(t, conn, "select id1 from t1 where id1 in (1, 2, 10)")
888+
889+
// Test: Rollback with tablet-specific routing
890+
utils.Exec(t, conn, fmt.Sprintf("USE ks@%s", primaryShard80Minus))
891+
utils.Exec(t, conn, "begin")
892+
utils.Exec(t, conn, "insert into t1(id1, id2) values(20, 400)")
893+
utils.Exec(t, conn, "rollback")
894+
// 20 should not exist
895+
utils.AssertIsEmpty(t, conn, "select id1 from t1 where id1=20")
896+
897+
// Test: Clear tablet targeting returns to normal routing
898+
utils.Exec(t, conn, "USE ks")
899+
utils.AssertMatches(t, conn, "select id1 from t1 where id1 in (1, 2, 10) order by id1", "[[INT64(1)] [INT64(2)] [INT64(10)]]")
900+
901+
// Cleanup
902+
utils.Exec(t, conn, "delete from t1 where id1 in (1, 2, 10)")
903+
}
904+
838905
// TestDynamicConfig tests the dynamic configurations.
839906
func TestDynamicConfig(t *testing.T) {
840907
t.Run("DiscoveryLowReplicationLag", func(t *testing.T) {

go/vt/topo/topoproto/destination_test.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func TestParseDestination(t *testing.T) {
3535
dest key.ShardDestination
3636
keyspace string
3737
tabletType topodatapb.TabletType
38+
tabletAlias *topodatapb.TabletAlias
3839
}{{
3940
targetString: "ks[10-20]@primary",
4041
keyspace: "ks",
@@ -87,18 +88,36 @@ func TestParseDestination(t *testing.T) {
8788
keyspace: "ks",
8889
dest: key.DestinationShard("-80"),
8990
tabletType: topodatapb.TabletType_PRIMARY,
91+
}, {
92+
targetString: "ks@zone1-0000000100",
93+
keyspace: "ks",
94+
tabletType: topodatapb.TabletType_PRIMARY,
95+
tabletAlias: &topodatapb.TabletAlias{Cell: "zone1", Uid: 100},
96+
}, {
97+
targetString: "ks:-80@zone1-0000000100",
98+
keyspace: "ks",
99+
dest: key.DestinationShard("-80"),
100+
tabletType: topodatapb.TabletType_PRIMARY,
101+
tabletAlias: &topodatapb.TabletAlias{Cell: "zone1", Uid: 100},
102+
}, {
103+
targetString: "@zone1-0000000200",
104+
keyspace: "",
105+
tabletType: topodatapb.TabletType_PRIMARY,
106+
tabletAlias: &topodatapb.TabletAlias{Cell: "zone1", Uid: 200},
90107
}}
91108

92109
for _, tcase := range testcases {
93-
if targetKeyspace, targetTabletType, targetDest, _, _ := ParseDestination(tcase.targetString, topodatapb.TabletType_PRIMARY); !reflect.DeepEqual(targetDest, tcase.dest) || targetKeyspace != tcase.keyspace || targetTabletType != tcase.tabletType {
94-
t.Errorf("ParseDestination(%s) - got: (%v, %v, %v), want (%v, %v, %v)",
110+
if targetKeyspace, targetTabletType, targetDest, targetAlias, _ := ParseDestination(tcase.targetString, topodatapb.TabletType_PRIMARY); !reflect.DeepEqual(targetDest, tcase.dest) || targetKeyspace != tcase.keyspace || targetTabletType != tcase.tabletType || !reflect.DeepEqual(targetAlias, tcase.tabletAlias) {
111+
t.Errorf("ParseDestination(%s) - got: (%v, %v, %v, %v), want (%v, %v, %v, %v)",
95112
tcase.targetString,
96-
targetDest,
97113
targetKeyspace,
98114
targetTabletType,
99-
tcase.dest,
115+
targetDest,
116+
targetAlias,
100117
tcase.keyspace,
101118
tcase.tabletType,
119+
tcase.dest,
120+
tcase.tabletAlias,
102121
)
103122
}
104123
}

go/vt/vtgate/executorcontext/safe_session_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,37 @@ func TestTimeZone(t *testing.T) {
205205
})
206206
}
207207
}
208+
209+
// TestTargetTabletAlias tests the SetTargetTabletAlias and GetTargetTabletAlias methods.
210+
func TestTargetTabletAlias(t *testing.T) {
211+
session := NewSafeSession(&vtgatepb.Session{})
212+
213+
// Test: initially nil
214+
assert.Nil(t, session.GetTargetTabletAlias())
215+
216+
// Test: Set and get
217+
alias := &topodatapb.TabletAlias{Cell: "zone1", Uid: 100}
218+
session.SetTargetTabletAlias(alias)
219+
got := session.GetTargetTabletAlias()
220+
assert.Equal(t, alias, got)
221+
222+
// Test: Clear (set to nil)
223+
session.SetTargetTabletAlias(nil)
224+
assert.Nil(t, session.GetTargetTabletAlias())
225+
226+
// Test: Thread safety - concurrent access
227+
done := make(chan bool)
228+
for i := 0; i < 100; i++ {
229+
go func(uid uint32) {
230+
testAlias := &topodatapb.TabletAlias{Cell: "cell", Uid: uid}
231+
session.SetTargetTabletAlias(testAlias)
232+
_ = session.GetTargetTabletAlias()
233+
done <- true
234+
}(uint32(i))
235+
}
236+
for i := 0; i < 100; i++ {
237+
<-done
238+
}
239+
// Just verify we didn't panic - the final value is non-deterministic
240+
assert.NotNil(t, session.GetTargetTabletAlias())
241+
}

go/vt/vtgate/scatter_conn_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,3 +632,68 @@ func TestIsConnClosed(t *testing.T) {
632632
})
633633
}
634634
}
635+
636+
// TestActionInfoWithTabletAlias tests the actionInfo function with tablet-specific routing.
637+
func TestActionInfoWithTabletAlias(t *testing.T) {
638+
ctx := utils.LeakCheckContext(t)
639+
target := &querypb.Target{
640+
Keyspace: "ks",
641+
Shard: "-80",
642+
TabletType: topodatapb.TabletType_PRIMARY,
643+
}
644+
tabletAlias := &topodatapb.TabletAlias{Cell: "zone1", Uid: 100}
645+
646+
t.Run("non-transactional with tablet alias", func(t *testing.T) {
647+
session := econtext.NewSafeSession(&vtgatepb.Session{})
648+
session.SetTargetTabletAlias(tabletAlias)
649+
650+
info, shardSession, err := actionInfo(ctx, target, session, false, vtgatepb.TransactionMode_MULTI)
651+
require.NoError(t, err)
652+
assert.Nil(t, shardSession)
653+
assert.Equal(t, nothing, info.actionNeeded)
654+
assert.Equal(t, tabletAlias, info.alias)
655+
})
656+
657+
t.Run("transaction begin with tablet alias", func(t *testing.T) {
658+
session := econtext.NewSafeSession(&vtgatepb.Session{
659+
InTransaction: true,
660+
})
661+
session.SetTargetTabletAlias(tabletAlias)
662+
663+
info, shardSession, err := actionInfo(ctx, target, session, false, vtgatepb.TransactionMode_MULTI)
664+
require.NoError(t, err)
665+
assert.Nil(t, shardSession)
666+
assert.Equal(t, begin, info.actionNeeded)
667+
assert.Equal(t, tabletAlias, info.alias)
668+
})
669+
670+
t.Run("existing transaction with tablet alias", func(t *testing.T) {
671+
session := econtext.NewSafeSession(&vtgatepb.Session{
672+
InTransaction: true,
673+
ShardSessions: []*vtgatepb.Session_ShardSession{{
674+
Target: target,
675+
TransactionId: 12345,
676+
TabletAlias: &topodatapb.TabletAlias{Cell: "zone1", Uid: 50},
677+
}},
678+
})
679+
session.SetTargetTabletAlias(tabletAlias)
680+
681+
info, shardSession, err := actionInfo(ctx, target, session, false, vtgatepb.TransactionMode_MULTI)
682+
require.NoError(t, err)
683+
assert.NotNil(t, shardSession)
684+
assert.Equal(t, int64(12345), info.transactionID)
685+
assert.Equal(t, nothing, info.actionNeeded)
686+
// Tablet alias should be overridden
687+
assert.Equal(t, tabletAlias, info.alias)
688+
})
689+
690+
t.Run("no tablet alias - existing behavior", func(t *testing.T) {
691+
session := econtext.NewSafeSession(&vtgatepb.Session{})
692+
693+
info, shardSession, err := actionInfo(ctx, target, session, false, vtgatepb.TransactionMode_MULTI)
694+
require.NoError(t, err)
695+
assert.Nil(t, shardSession)
696+
assert.Equal(t, nothing, info.actionNeeded)
697+
assert.Nil(t, info.alias)
698+
})
699+
}

0 commit comments

Comments
 (0)