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  }