github.com/lfch/etcd-io/tests/v3@v3.0.0-20221004140520-eac99acd3e9d/common/lease_test.go (about) 1 // Copyright 2022 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package common 16 17 import ( 18 "context" 19 "testing" 20 "time" 21 22 clientv3 "github.com/lfch/etcd-io/client/v3" 23 "github.com/lfch/etcd-io/tests/v3/framework" 24 "github.com/lfch/etcd-io/tests/v3/framework/config" 25 "github.com/lfch/etcd-io/tests/v3/framework/testutils" 26 "github.com/stretchr/testify/require" 27 ) 28 29 func TestLeaseGrantTimeToLive(t *testing.T) { 30 testRunner.BeforeTest(t) 31 32 tcs := []struct { 33 name string 34 config config.ClusterConfig 35 }{ 36 { 37 name: "NoTLS", 38 config: config.ClusterConfig{ClusterSize: 1}, 39 }, 40 { 41 name: "PeerTLS", 42 config: config.ClusterConfig{ClusterSize: 3, PeerTLS: config.ManualTLS}, 43 }, 44 { 45 name: "PeerAutoTLS", 46 config: config.ClusterConfig{ClusterSize: 3, PeerTLS: config.AutoTLS}, 47 }, 48 { 49 name: "ClientTLS", 50 config: config.ClusterConfig{ClusterSize: 1, ClientTLS: config.ManualTLS}, 51 }, 52 { 53 name: "ClientAutoTLS", 54 config: config.ClusterConfig{ClusterSize: 1, ClientTLS: config.AutoTLS}, 55 }, 56 } 57 for _, tc := range tcs { 58 t.Run(tc.name, func(t *testing.T) { 59 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 60 defer cancel() 61 clus := testRunner.NewCluster(ctx, t, tc.config) 62 defer clus.Close() 63 cc := framework.MustClient(clus.Client(clientv3.AuthConfig{})) 64 65 testutils.ExecuteUntil(ctx, t, func() { 66 ttl := int64(10) 67 leaseResp, err := cc.Grant(ctx, ttl) 68 require.NoError(t, err) 69 70 ttlResp, err := cc.TimeToLive(ctx, leaseResp.ID, config.LeaseOption{}) 71 require.NoError(t, err) 72 require.Equal(t, ttl, ttlResp.GrantedTTL) 73 }) 74 }) 75 } 76 } 77 78 func TestLeaseGrantAndList(t *testing.T) { 79 testRunner.BeforeTest(t) 80 81 for _, tc := range clusterTestCases { 82 nestedCases := []struct { 83 name string 84 leaseCount int 85 }{ 86 { 87 name: "no_leases", 88 leaseCount: 0, 89 }, 90 { 91 name: "one_lease", 92 leaseCount: 1, 93 }, 94 { 95 name: "many_leases", 96 leaseCount: 3, 97 }, 98 } 99 100 for _, nc := range nestedCases { 101 t.Run(tc.name+"/"+nc.name, func(t *testing.T) { 102 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 103 defer cancel() 104 t.Logf("Creating cluster...") 105 clus := testRunner.NewCluster(ctx, t, tc.config) 106 defer clus.Close() 107 cc := framework.MustClient(clus.Client(clientv3.AuthConfig{})) 108 t.Logf("Created cluster and client") 109 testutils.ExecuteUntil(ctx, t, func() { 110 var createdLeases []clientv3.LeaseID 111 for i := 0; i < nc.leaseCount; i++ { 112 leaseResp, err := cc.Grant(ctx, 10) 113 t.Logf("Grant returned: resp:%s err:%v", leaseResp.String(), err) 114 require.NoError(t, err) 115 createdLeases = append(createdLeases, leaseResp.ID) 116 } 117 118 // Because we're not guarunteed to talk to the same member, wait for 119 // listing to eventually return true, either by the result propagaing 120 // or by hitting an up to date member. 121 var leases []clientv3.LeaseStatus 122 require.Eventually(t, func() bool { 123 resp, err := cc.Leases(ctx) 124 if err != nil { 125 return false 126 } 127 leases = resp.Leases 128 // TODO: update this to use last Revision from leaseResp 129 // after https://github.com/etcd-io/etcd/issues/13989 is fixed 130 return len(leases) == len(createdLeases) 131 }, 2*time.Second, 10*time.Millisecond) 132 133 returnedLeases := make([]clientv3.LeaseID, 0, nc.leaseCount) 134 for _, status := range leases { 135 returnedLeases = append(returnedLeases, status.ID) 136 } 137 138 require.ElementsMatch(t, createdLeases, returnedLeases) 139 }) 140 }) 141 } 142 } 143 } 144 145 func TestLeaseGrantTimeToLiveExpired(t *testing.T) { 146 testRunner.BeforeTest(t) 147 148 for _, tc := range clusterTestCases { 149 t.Run(tc.name, func(t *testing.T) { 150 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 151 defer cancel() 152 clus := testRunner.NewCluster(ctx, t, tc.config) 153 defer clus.Close() 154 cc := framework.MustClient(clus.Client(clientv3.AuthConfig{})) 155 156 testutils.ExecuteUntil(ctx, t, func() { 157 leaseResp, err := cc.Grant(ctx, 2) 158 require.NoError(t, err) 159 160 err = cc.Put(ctx, "foo", "bar", config.PutOptions{LeaseID: leaseResp.ID}) 161 require.NoError(t, err) 162 163 getResp, err := cc.Get(ctx, "foo", config.GetOptions{}) 164 require.NoError(t, err) 165 require.Equal(t, int64(1), getResp.Count) 166 167 time.Sleep(3 * time.Second) 168 169 ttlResp, err := cc.TimeToLive(ctx, leaseResp.ID, config.LeaseOption{}) 170 require.NoError(t, err) 171 require.Equal(t, int64(-1), ttlResp.TTL) 172 173 getResp, err = cc.Get(ctx, "foo", config.GetOptions{}) 174 require.NoError(t, err) 175 // Value should expire with the lease 176 require.Equal(t, int64(0), getResp.Count) 177 }) 178 }) 179 } 180 } 181 182 func TestLeaseGrantKeepAliveOnce(t *testing.T) { 183 testRunner.BeforeTest(t) 184 185 for _, tc := range clusterTestCases { 186 t.Run(tc.name, func(t *testing.T) { 187 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 188 defer cancel() 189 clus := testRunner.NewCluster(ctx, t, tc.config) 190 defer clus.Close() 191 cc := framework.MustClient(clus.Client(clientv3.AuthConfig{})) 192 193 testutils.ExecuteUntil(ctx, t, func() { 194 leaseResp, err := cc.Grant(ctx, 2) 195 require.NoError(t, err) 196 197 _, err = cc.KeepAliveOnce(ctx, leaseResp.ID) 198 require.NoError(t, err) 199 200 time.Sleep(2 * time.Second) // Wait for the original lease to expire 201 202 ttlResp, err := cc.TimeToLive(ctx, leaseResp.ID, config.LeaseOption{}) 203 require.NoError(t, err) 204 // We still have a lease! 205 require.Greater(t, int64(2), ttlResp.TTL) 206 }) 207 }) 208 } 209 } 210 211 func TestLeaseGrantRevoke(t *testing.T) { 212 testRunner.BeforeTest(t) 213 214 for _, tc := range clusterTestCases { 215 t.Run(tc.name, func(t *testing.T) { 216 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 217 defer cancel() 218 clus := testRunner.NewCluster(ctx, t, tc.config) 219 defer clus.Close() 220 cc := framework.MustClient(clus.Client(clientv3.AuthConfig{})) 221 222 testutils.ExecuteUntil(ctx, t, func() { 223 leaseResp, err := cc.Grant(ctx, 20) 224 require.NoError(t, err) 225 226 err = cc.Put(ctx, "foo", "bar", config.PutOptions{LeaseID: leaseResp.ID}) 227 require.NoError(t, err) 228 229 getResp, err := cc.Get(ctx, "foo", config.GetOptions{}) 230 require.NoError(t, err) 231 require.Equal(t, int64(1), getResp.Count) 232 233 _, err = cc.Revoke(ctx, leaseResp.ID) 234 require.NoError(t, err) 235 236 ttlResp, err := cc.TimeToLive(ctx, leaseResp.ID, config.LeaseOption{}) 237 require.NoError(t, err) 238 require.Equal(t, int64(-1), ttlResp.TTL) 239 240 getResp, err = cc.Get(ctx, "foo", config.GetOptions{}) 241 require.NoError(t, err) 242 // Value should expire with the lease 243 require.Equal(t, int64(0), getResp.Count) 244 }) 245 }) 246 } 247 }