@@ -24,6 +24,7 @@ import (
2424 "github.com/stretchr/testify/assert"
2525 "github.com/stretchr/testify/require"
2626
27+ "go.etcd.io/etcd/api/v3/v3rpc/rpctypes"
2728 clientv3 "go.etcd.io/etcd/client/v3"
2829 "go.etcd.io/etcd/tests/v3/framework/e2e"
2930 "go.etcd.io/etcd/tests/v3/framework/testutils"
@@ -164,3 +165,60 @@ func testLeaseRevokeIssue(t *testing.T, clusterSize int, connectToOneFollower bo
164165 close (stopC )
165166 <- doneC
166167}
168+
169+ func TestLeaseRevokeDuringRenew (t * testing.T ) {
170+ e2e .BeforeTest (t )
171+
172+ ctx := t .Context ()
173+
174+ t .Log ("Starting a new etcd cluster" )
175+ epc , err := e2e .NewEtcdProcessCluster (ctx , t ,
176+ e2e .WithClusterSize (1 ),
177+ e2e .WithGoFailEnabled (true ),
178+ e2e .WithGoFailClientTimeout (40 * time .Second ),
179+ )
180+ require .NoError (t , err )
181+ defer func () {
182+ require .NoErrorf (t , epc .Close (), "error closing etcd processes" )
183+ }()
184+
185+ eps := epc .Procs [0 ].EndpointsGRPC ()
186+ t .Logf ("Creating two clients for lease operations: %v" , eps )
187+ clientForRenew , err := clientv3 .New (clientv3.Config {Endpoints : eps , DialTimeout : 3 * time .Second })
188+ require .NoError (t , err )
189+ defer clientForRenew .Close ()
190+
191+ clientForRevoke , err := clientv3 .New (clientv3.Config {Endpoints : eps , DialTimeout : 3 * time .Second })
192+ require .NoError (t , err )
193+ defer clientForRevoke .Close ()
194+
195+ t .Log ("Creating a new lease" )
196+ leaseRsp , err := clientForRenew .Grant (ctx , 60 )
197+ require .NoError (t , err )
198+
199+ t .Log ("Activate the 'beforeCheckpointInLeaseRenew' failpoint" )
200+ require .NoError (t , epc .Procs [0 ].Failpoints ().SetupHTTP (ctx , "beforeCheckpointInLeaseRenew" , `sleep("3s")` ))
201+
202+ t .Logf ("Starting a goroutine to keep alive the lease: %d" , leaseRsp .ID )
203+ doneC := make (chan struct {})
204+ startC := make (chan struct {}, 1 )
205+ var renewError error
206+ go func () {
207+ defer close (doneC )
208+ startC <- struct {}{}
209+ _ , renewError = clientForRenew .KeepAliveOnce (ctx , leaseRsp .ID )
210+ }()
211+
212+ t .Log ("Wait for the KeepAliveOnce goroutine to get started" )
213+ <- startC
214+ time .Sleep (200 * time .Millisecond )
215+
216+ t .Logf ("Revoke the lease: %d" , leaseRsp .ID )
217+ _ , lerr := clientForRevoke .Revoke (ctx , leaseRsp .ID )
218+ require .NoError (t , lerr )
219+
220+ t .Log ("Waiting for the keepAlive goroutine to exit" )
221+ <- doneC
222+
223+ require .ErrorIs (t , rpctypes .ErrLeaseNotFound , renewError )
224+ }
0 commit comments