forked from vitessio/vitess
-
Notifications
You must be signed in to change notification settings - Fork 0
/
faketopo.go
157 lines (137 loc) · 4.03 KB
/
faketopo.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// faketopo contains utitlities for tests that have to interact with a
// Vitess topology.
package faketopo
import (
"fmt"
"testing"
"time"
"github.com/youtube/vitess/go/vt/key"
"github.com/youtube/vitess/go/vt/mysqlctl"
"github.com/youtube/vitess/go/vt/tabletmanager/actionnode"
"github.com/youtube/vitess/go/vt/tabletmanager/actor"
"github.com/youtube/vitess/go/vt/topo"
"github.com/youtube/vitess/go/vt/wrangler"
"github.com/youtube/vitess/go/vt/zktopo"
)
const (
TestShard = "-80"
TestKeyspace = "test_keyspace"
)
func newKeyRange(value string) key.KeyRange {
_, result, err := topo.ValidateShardName(value)
if err != nil {
panic(err)
}
return result
}
type tabletPack struct {
*topo.Tablet
mysql *mysqlctl.FakeMysqlDaemon
}
// Fixture is a fixture that provides a fresh topology, to which you
// can add tablets that react to events and have fake MySQL
// daemons. It uses an in memory fake ZooKeeper to store its
// data. When you are done with the fixture you have to call its
// TearDown method.
type Fixture struct {
*testing.T
tablets map[int]*tabletPack
done chan struct{}
Topo topo.Server
Wrangler *wrangler.Wrangler
}
// New creates a topology fixture.
func New(t *testing.T, cells []string) *Fixture {
ts := zktopo.NewTestServer(t, cells)
wr := wrangler.New(ts, 1*time.Second, 1*time.Second)
wr.UseRPCs = false
return &Fixture{
T: t,
Topo: ts,
Wrangler: wr,
done: make(chan struct{}, 1),
tablets: make(map[int]*tabletPack),
}
}
// TearDown releases any resources used by the fixture.
func (fix *Fixture) TearDown() {
close(fix.done)
}
// startFakeTabletActionLoop will start the action loop for a fake
// tablet.
func (fix *Fixture) startFakeTabletActionLoop(tablet *tabletPack) {
go func() {
f := func(actionPath, data string) error {
actionNode, err := actionnode.ActionNodeFromJson(data, actionPath)
if err != nil {
fix.Fatalf("ActionNodeFromJson failed: %v\n%v", err, data)
}
ta := actor.NewTabletActor(nil, tablet.mysql, fix.Topo, tablet.Alias)
if err := ta.HandleAction(actionPath, actionNode.Action, actionNode.ActionGuid, false); err != nil {
// action may just fail for any good reason
fix.Logf("HandleAction failed for %v: %v", actionNode.Action, err)
}
return nil
}
fix.Topo.ActionEventLoop(tablet.Alias, f, fix.done)
}()
}
// MakeMySQLMaster makes the (fake) MySQL used by tablet identified by
// uid the master.
func (fix *Fixture) MakeMySQLMaster(uid int) {
newMaster, ok := fix.tablets[uid]
if !ok {
fix.Fatalf("bad tablet uid: %v", uid)
}
for id, tablet := range fix.tablets {
if id == uid {
tablet.mysql.MasterAddr = ""
} else {
tablet.mysql.MasterAddr = newMaster.MysqlIpAddr()
}
}
}
// AddTablet adds a new tablet to the topology and starts its event
// loop.
func (fix *Fixture) AddTablet(uid int, cell string, tabletType topo.TabletType, master *topo.Tablet) *topo.Tablet {
tablet := &topo.Tablet{
Alias: topo.TabletAlias{Cell: cell, Uid: uint32(uid)},
Hostname: fmt.Sprintf("%vbsr%v", cell, uid),
IPAddr: fmt.Sprintf("212.244.218.%v", uid),
Portmap: map[string]int{
"vt": 3333 + 10*uid,
"mysql": 3334 + 10*uid,
},
Keyspace: TestKeyspace,
Type: tabletType,
Shard: TestShard,
KeyRange: newKeyRange(TestShard),
}
if master != nil {
tablet.Parent = master.Alias
}
if err := fix.Wrangler.InitTablet(tablet, true, true, false); err != nil {
fix.Fatalf("CreateTablet: %v", err)
}
mysqlDaemon := &mysqlctl.FakeMysqlDaemon{}
if master != nil {
mysqlDaemon.MasterAddr = master.MysqlIpAddr()
}
mysqlDaemon.MysqlPort = 3334 + 10*uid
pack := &tabletPack{Tablet: tablet, mysql: mysqlDaemon}
fix.startFakeTabletActionLoop(pack)
fix.tablets[uid] = pack
return tablet
}
// GetTablet returns a fresh copy of the tablet identified by uid.
func (fix *Fixture) GetTablet(uid int) *topo.TabletInfo {
tablet, ok := fix.tablets[uid]
if !ok {
panic("bad tablet uid")
}
ti, err := fix.Topo.GetTablet(tablet.Alias)
if err != nil {
fix.Fatalf("GetTablet %v: %v", tablet.Alias, err)
}
return ti
}