Skip to content

Commit

Permalink
robustness: add mix version scenario with fixed leader.
Browse files Browse the repository at this point in the history
Signed-off-by: Siyuan Zhang <[email protected]>
  • Loading branch information
siyuanfoundation committed May 17, 2024
1 parent 62d8145 commit bf78d07
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 9 deletions.
55 changes: 48 additions & 7 deletions tests/framework/e2e/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,11 @@ type EtcdProcessClusterConfig struct {

// Cluster setup config

ClusterSize int
RollingStart bool
ClusterSize int
// InitialLeaderIndex, if specified (>=0), makes sure the leader is the ith proc
// when the cluster starts.
InitialLeaderIndex int
RollingStart bool
// BaseDataDirPath specifies the data-dir for the members. If test cases
// do not specify `BaseDataDirPath`, then e2e framework creates a
// temporary directory for each member; otherwise, it creates a
Expand Down Expand Up @@ -180,10 +183,10 @@ type EtcdProcessClusterConfig struct {

func DefaultConfig() *EtcdProcessClusterConfig {
cfg := &EtcdProcessClusterConfig{
ClusterSize: 3,
CN: true,

ServerConfig: *embed.NewConfig(),
ClusterSize: 3,
CN: true,
InitialLeaderIndex: -1,
ServerConfig: *embed.NewConfig(),
}
cfg.ServerConfig.InitialClusterToken = "new"
return cfg
Expand All @@ -207,6 +210,10 @@ func WithVersion(version ClusterVersion) EPClusterOption {
return func(c *EtcdProcessClusterConfig) { c.Version = version }
}

func WithInitialLeaderIndex(i int) EPClusterOption {
return func(c *EtcdProcessClusterConfig) { c.InitialLeaderIndex = i }
}

func WithDataDirPath(path string) EPClusterOption {
return func(c *EtcdProcessClusterConfig) { c.BaseDataDirPath = path }
}
Expand Down Expand Up @@ -437,7 +444,11 @@ func StartEtcdProcessCluster(ctx context.Context, t testing.TB, epc *EtcdProcess
t.Skip("please run 'make gofail-enable && make build' before running the test")
}
}

if cfg.InitialLeaderIndex >= 0 {
if err := epc.MoveLeader(t, cfg.InitialLeaderIndex); err != nil {
return nil, fmt.Errorf("failed to move leader: %v", err)
}
}
return epc, nil
}

Expand Down Expand Up @@ -1050,3 +1061,33 @@ func (epc *EtcdProcessCluster) WaitMembersForLeader(ctx context.Context, t testi
t.Fatal("impossible path of execution")
return -1
}

// MoveLeader moves the leader to the ith process.
func (epc *EtcdProcessCluster) MoveLeader(t testing.TB, i int) error {
if i < 0 || i >= len(epc.Procs) {
return fmt.Errorf("invalid index: %d, must between 0 and %d", i, len(epc.Procs)-1)
}
t.Logf("moving leader to Procs[%d]", i)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
oldLeader := epc.WaitMembersForLeader(ctx, t, epc.Procs)
if oldLeader == i {
t.Logf("Procs[%d] is already the leader", i)
return nil
}
resp, err := epc.Procs[i].Etcdctl().Status(ctx)
if err != nil {
return err
}
memberID := resp[0].Header.MemberId
err = epc.Procs[oldLeader].Etcdctl().MoveLeader(ctx, memberID)
if err != nil {
return err
}
newLeader := epc.WaitMembersForLeader(ctx, t, epc.Procs)
if newLeader != i {
t.Fatalf("expect new leader to be Procs[%d] but got Procs[%d]", i, newLeader)
}
t.Logf("moved leader from Procs[%d] to Procs[%d]", oldLeader, i)
return nil
}
7 changes: 7 additions & 0 deletions tests/framework/e2e/etcdctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,13 @@ func (ctl *EtcdctlV3) MemberPromote(ctx context.Context, id uint64) (*clientv3.M
return &resp, err
}

// MoveLeader requests current leader to transfer its leadership to the transferee.
// Request must be made to the leader.
func (ctl *EtcdctlV3) MoveLeader(ctx context.Context, transfereeID uint64) error {
_, err := SpawnWithExpectLines(ctx, ctl.cmdArgs("move-leader", fmt.Sprintf("%x", transfereeID)), nil, expect.ExpectedResponse{Value: "Leadership transferred"})
return err
}

func (ctl *EtcdctlV3) cmdArgs(args ...string) []string {
cmdArgs := []string{BinPath.Etcdctl}
for k, v := range ctl.flags() {
Expand Down
4 changes: 4 additions & 0 deletions tests/robustness/options/server_config_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,7 @@ func WithExperimentalWatchProgressNotifyInterval(input ...time.Duration) e2e.EPC
func WithVersion(input ...e2e.ClusterVersion) e2e.EPClusterOption {
return func(c *e2e.EtcdProcessClusterConfig) { c.Version = input[internalRand.Intn(len(input))] }
}

func WithInitialLeaderIndex(input ...int) e2e.EPClusterOption {
return func(c *e2e.EtcdProcessClusterConfig) { c.InitialLeaderIndex = input[internalRand.Intn(len(input))] }
}
14 changes: 12 additions & 2 deletions tests/robustness/scenarios.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,18 @@ func exploratoryScenarios(_ *testing.T) []testScenario {
}

// 66% current version, 33% MinorityLastVersion and QuorumLastVersion
mixedVersionOption := options.WithVersion(e2e.CurrentVersion, e2e.CurrentVersion, e2e.CurrentVersion,
e2e.CurrentVersion, e2e.MinorityLastVersion, e2e.QuorumLastVersion)
mixedVersionOption := options.WithClusterOptionGroups(
// 60% with all members of current version
options.ClusterOptions{options.WithVersion(e2e.CurrentVersion)},
options.ClusterOptions{options.WithVersion(e2e.CurrentVersion)},
options.ClusterOptions{options.WithVersion(e2e.CurrentVersion)},
// 10% with 2 members of current version, 1 member last version, leader is current version
// 10% with 2 members of current version, 1 member last version, leader is last version
options.ClusterOptions{options.WithVersion(e2e.MinorityLastVersion), options.WithInitialLeaderIndex(0, 2)},
// 10% with 2 members of last version, 1 member current version, leader is last version
// 10% with 2 members of last version, 1 member current version, leader is current version
options.ClusterOptions{options.WithVersion(e2e.QuorumLastVersion), options.WithInitialLeaderIndex(0, 2)},
)

baseOptions := []e2e.EPClusterOption{
options.WithSnapshotCount(50, 100, 1000),
Expand Down

0 comments on commit bf78d07

Please sign in to comment.