From 3c582fecb07dfa0c8bda0856f6a07bd261bfefb5 Mon Sep 17 00:00:00 2001 From: Ramil Mirhasanov Date: Wed, 14 Dec 2022 11:10:54 +0300 Subject: [PATCH] clientv3/concurrency: add logger to session, add unit test Signed-off-by: Ramil Mirhasanov --- client/v3/concurrency/session.go | 14 ++-- .../clientv3/concurrency/session_test.go | 84 +++++++++++++++++++ 2 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 tests/integration/clientv3/concurrency/session_test.go diff --git a/client/v3/concurrency/session.go b/client/v3/concurrency/session.go index 7143cc474..8ab482077 100644 --- a/client/v3/concurrency/session.go +++ b/client/v3/concurrency/session.go @@ -19,6 +19,7 @@ import ( "time" v3 "go.etcd.io/etcd/client/v3" + "go.uber.org/zap" ) const defaultSessionTTL = 60 @@ -36,9 +37,10 @@ type Session struct { // NewSession gets the leased session for a client. func NewSession(client *v3.Client, opts ...SessionOption) (*Session, error) { + lg := client.GetLogger() ops := &sessionOptions{ttl: defaultSessionTTL, ctx: client.Ctx()} for _, opt := range opts { - opt(ops) + opt(ops, lg) } id := ops.leaseID @@ -108,14 +110,16 @@ type sessionOptions struct { } // SessionOption configures Session. -type SessionOption func(*sessionOptions) +type SessionOption func(*sessionOptions, *zap.Logger) // WithTTL configures the session's TTL in seconds. // If TTL is <= 0, the default 60 seconds TTL will be used. func WithTTL(ttl int) SessionOption { - return func(so *sessionOptions) { + return func(so *sessionOptions, lg *zap.Logger) { if ttl > 0 { so.ttl = ttl + } else { + lg.Warn("WithTTL(): TTL should be > 0, preserving current TTL", zap.Int64("current-session-ttl", int64(so.ttl))) } } } @@ -124,7 +128,7 @@ func WithTTL(ttl int) SessionOption { // This is useful in process restart scenario, for example, to reclaim // leadership from an election prior to restart. func WithLease(leaseID v3.LeaseID) SessionOption { - return func(so *sessionOptions) { + return func(so *sessionOptions, _ *zap.Logger) { so.leaseID = leaseID } } @@ -135,7 +139,7 @@ func WithLease(leaseID v3.LeaseID) SessionOption { // context is canceled before Close() completes, the session's lease will be // abandoned and left to expire instead of being revoked. func WithContext(ctx context.Context) SessionOption { - return func(so *sessionOptions) { + return func(so *sessionOptions, _ *zap.Logger) { so.ctx = ctx } } diff --git a/tests/integration/clientv3/concurrency/session_test.go b/tests/integration/clientv3/concurrency/session_test.go new file mode 100644 index 000000000..d1ca41320 --- /dev/null +++ b/tests/integration/clientv3/concurrency/session_test.go @@ -0,0 +1,84 @@ +// Copyright 2022 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package concurrency_test + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + clientv3 "go.etcd.io/etcd/client/v3" + "go.etcd.io/etcd/client/v3/concurrency" + integration2 "go.etcd.io/etcd/tests/v3/framework/integration" +) + +func TestSessionOptions(t *testing.T) { + cli, err := integration2.NewClient(t, clientv3.Config{Endpoints: exampleEndpoints()}) + if err != nil { + t.Fatal(err) + } + defer cli.Close() + lease, err := cli.Grant(context.Background(), 100) + if err != nil { + t.Fatal(err) + } + s, err := concurrency.NewSession(cli, concurrency.WithLease(lease.ID)) + if err != nil { + t.Fatal(err) + } + defer s.Close() + assert.Equal(t, s.Lease(), lease.ID) + + go s.Orphan() + select { + case <-s.Done(): + case <-time.After(time.Millisecond * 100): + t.Fatal("session did not get orphaned as expected") + } + +} +func TestSessionTTLOptions(t *testing.T) { + cli, err := integration2.NewClient(t, clientv3.Config{Endpoints: exampleEndpoints()}) + if err != nil { + t.Fatal(err) + } + defer cli.Close() + + var setTTL int = 90 + s, err := concurrency.NewSession(cli, concurrency.WithTTL(setTTL)) + if err != nil { + t.Fatal(err) + } + defer s.Close() + + leaseId := s.Lease() + // TTL retrieved should be less than the set TTL, but not equal to default:60 or exprired:-1 + resp, err := cli.Lease.TimeToLive(context.Background(), leaseId) + if err != nil { + t.Log(err) + } + if resp.TTL == -1 { + t.Errorf("client lease should not be expired: %d", resp.TTL) + + } + if resp.TTL == 60 { + t.Errorf("default TTL value is used in the session, instead of set TTL: %d", setTTL) + } + if resp.TTL >= int64(setTTL) || resp.TTL < int64(setTTL)-20 { + t.Errorf("Session TTL from lease should be less, but close to set TTL %d, have: %d", setTTL, resp.TTL) + } + +}