@@ -22,6 +22,8 @@ import (
22
22
"testing"
23
23
"time"
24
24
25
+ "github.com/stretchr/testify/assert"
26
+ "github.com/stretchr/testify/require"
25
27
"google.golang.org/grpc/codes"
26
28
"google.golang.org/grpc/metadata"
27
29
"google.golang.org/grpc/status"
@@ -30,8 +32,10 @@ import (
30
32
"go.etcd.io/etcd/api/v3/mvccpb"
31
33
"go.etcd.io/etcd/api/v3/v3rpc/rpctypes"
32
34
"go.etcd.io/etcd/client/pkg/v3/testutil"
35
+ clientv3 "go.etcd.io/etcd/client/v3"
33
36
framecfg "go.etcd.io/etcd/tests/v3/framework/config"
34
37
"go.etcd.io/etcd/tests/v3/framework/integration"
38
+ gofail "go.etcd.io/gofail/runtime"
35
39
)
36
40
37
41
// TestV3LeasePromote ensures the newly elected leader can promote itself
@@ -1046,6 +1050,78 @@ func TestV3LeaseRecoverKeyWithMutipleLease(t *testing.T) {
1046
1050
}
1047
1051
}
1048
1052
1053
+ func TestV3LeaseTimeToLiveWithLeaderChanged (t * testing.T ) {
1054
+ t .Run ("normal" , func (subT * testing.T ) {
1055
+ testV3LeaseTimeToLiveWithLeaderChanged (subT , "beforeLookupWhenLeaseTimeToLive" )
1056
+ })
1057
+
1058
+ t .Run ("forward" , func (subT * testing.T ) {
1059
+ testV3LeaseTimeToLiveWithLeaderChanged (subT , "beforeLookupWhenForwardLeaseTimeToLive" )
1060
+ })
1061
+ }
1062
+
1063
+ func testV3LeaseTimeToLiveWithLeaderChanged (t * testing.T , fpName string ) {
1064
+ if len (gofail .List ()) == 0 {
1065
+ t .Skip ("please run 'make gofail-enable' before running the test" )
1066
+ }
1067
+
1068
+ integration .BeforeTest (t )
1069
+
1070
+ clus := integration .NewCluster (t , & integration.ClusterConfig {Size : 3 })
1071
+ defer clus .Terminate (t )
1072
+
1073
+ ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
1074
+ defer cancel ()
1075
+
1076
+ oldLeadIdx := clus .WaitLeader (t )
1077
+ followerIdx := (oldLeadIdx + 1 ) % 3
1078
+
1079
+ followerMemberID := clus .Members [followerIdx ].ID ()
1080
+
1081
+ oldLeadC := clus .Client (oldLeadIdx )
1082
+
1083
+ leaseResp , err := oldLeadC .Grant (ctx , 100 )
1084
+ require .NoError (t , err )
1085
+
1086
+ require .NoError (t , gofail .Enable (fpName , `sleep("3s")` ))
1087
+ t .Cleanup (func () {
1088
+ terr := gofail .Disable (fpName )
1089
+ if terr != nil && terr != gofail .ErrDisabled {
1090
+ t .Fatalf ("failed to disable %s: %v" , fpName , terr )
1091
+ }
1092
+ })
1093
+
1094
+ readyCh := make (chan struct {})
1095
+ errCh := make (chan error , 1 )
1096
+
1097
+ var targetC * clientv3.Client
1098
+ switch fpName {
1099
+ case "beforeLookupWhenLeaseTimeToLive" :
1100
+ targetC = oldLeadC
1101
+ case "beforeLookupWhenForwardLeaseTimeToLive" :
1102
+ targetC = clus .Client ((oldLeadIdx + 2 ) % 3 )
1103
+ default :
1104
+ t .Fatalf ("unsupported %s failpoint" , fpName )
1105
+ }
1106
+
1107
+ go func () {
1108
+ <- readyCh
1109
+ time .Sleep (1 * time .Second )
1110
+
1111
+ _ , merr := oldLeadC .MoveLeader (ctx , uint64 (followerMemberID ))
1112
+ assert .NoError (t , gofail .Disable (fpName ))
1113
+ errCh <- merr
1114
+ }()
1115
+
1116
+ close (readyCh )
1117
+
1118
+ ttlResp , err := targetC .TimeToLive (ctx , leaseResp .ID )
1119
+ require .NoError (t , err )
1120
+ require .GreaterOrEqual (t , int64 (100 ), ttlResp .TTL )
1121
+
1122
+ require .NoError (t , <- errCh )
1123
+ }
1124
+
1049
1125
// acquireLeaseAndKey creates a new lease and creates an attached key.
1050
1126
func acquireLeaseAndKey (clus * integration.Cluster , key string ) (int64 , error ) {
1051
1127
// create lease
0 commit comments