Skip to content

Commit 6339219

Browse files
amosehiguesek8s-infra-cherrypick-robot
authored andcommitted
Add test for panic-free removal of non-existent members
This test verifies that etcd no longer panics when restarting after removing a member that was already removed from the cluster. addresses: issue #13715 Signed-off-by: amosehiguese <[email protected]>
1 parent 115f15e commit 6339219

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed

tests/integration/member_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,46 @@ func TestRemoveMember(t *testing.T) {
132132
checkMemberCount(t, c.Members[1], 2)
133133
}
134134

135+
// TestRemoveMemberAndWALReplay ensures that etcd can properly handle
136+
// member removal followed by restart with WAL replay, ensuring no panics
137+
// occur when replaying already-applied removal operations.
138+
func TestRemoveMemberAndWALReplay(t *testing.T) {
139+
integration.BeforeTest(t)
140+
141+
// Create a cluster with 3 member and a low snapshot count
142+
c := integration.NewCluster(t, &integration.ClusterConfig{
143+
Size: 3,
144+
SnapshotCount: 10,
145+
UseBridge: true,
146+
DisableStrictReconfigCheck: true,
147+
})
148+
defer c.Terminate(t)
149+
150+
// Add some k/v to trigger snapshot
151+
for i := 0; i < 15; i++ {
152+
ctx, cancel := context.WithTimeout(context.Background(), integration.RequestTimeout)
153+
_, err := c.Members[0].Client.Put(ctx, fmt.Sprintf("k%d", i), fmt.Sprintf("v%d", i))
154+
cancel()
155+
require.NoErrorf(t, err, "failed to put key-value")
156+
}
157+
158+
// Record the ID of the member we'll remove
159+
memberToRemoveID := uint64(c.Members[2].Server.MemberID())
160+
161+
// Remove one member from the cluster
162+
err := c.RemoveMember(t, c.Members[0].Client, memberToRemoveID)
163+
require.NoErrorf(t, err, "failed to remove member")
164+
165+
// Stop the remaining members
166+
c.Members[0].Stop(t)
167+
c.Members[1].Stop(t)
168+
169+
// Restart one member - this would previously panic when loading
170+
// WAL entries that try to remove an already removed member
171+
err = c.Members[0].Restart(t)
172+
require.NoErrorf(t, err, "failed to restart member after removal")
173+
}
174+
135175
func checkMemberCount(t *testing.T, m *integration.Member, expectedMemberCount int) {
136176
be := schema.NewMembershipBackend(m.Logger, m.Server.Backend())
137177
membersFromBackend, _ := be.MustReadMembersFromBackend()

0 commit comments

Comments
 (0)