From fdd9a5c27cb9304f248b7175cc356cdfdc1b051f Mon Sep 17 00:00:00 2001 From: Shafeeque E S Date: Thu, 21 Nov 2024 10:43:17 +0530 Subject: [PATCH] Use fakeClock in subresourceClient --- pkg/client/fake/client.go | 18 ++++++++++++++++-- pkg/client/fake/client_test.go | 31 ++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/pkg/client/fake/client.go b/pkg/client/fake/client.go index 05b52d0c5f..0e28dcef5a 100644 --- a/pkg/client/fake/client.go +++ b/pkg/client/fake/client.go @@ -53,6 +53,7 @@ import ( "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/testing" + "k8s.io/utils/clock" "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" @@ -77,6 +78,7 @@ type fakeClient struct { schemeWriteLock sync.Mutex scheme *runtime.Scheme + clock clock.Clock restMapper meta.RESTMapper withStatusSubresource sets.Set[schema.GroupVersionKind] @@ -110,6 +112,7 @@ func NewClientBuilder() *ClientBuilder { // ClientBuilder builds a fake client. type ClientBuilder struct { scheme *runtime.Scheme + clock clock.Clock restMapper meta.RESTMapper initObject []client.Object initLists []client.ObjectList @@ -130,6 +133,13 @@ func (f *ClientBuilder) WithScheme(scheme *runtime.Scheme) *ClientBuilder { return f } +// WithClock sets this builder's internal clock. +// If not set, defaults to clock.RealClock. +func (f *ClientBuilder) WithClock(clock clock.Clock) *ClientBuilder { + f.clock = clock + return f +} + // WithRESTMapper sets this builder's restMapper. // The restMapper is directly set as mapper in the Client. This can be used for example // with a meta.DefaultRESTMapper to provide a static rest mapping. @@ -222,6 +232,9 @@ func (f *ClientBuilder) Build() client.WithWatch { if f.restMapper == nil { f.restMapper = meta.NewDefaultRESTMapper([]schema.GroupVersion{}) } + if f.clock == nil { + f.clock = clock.RealClock{} + } var tracker versionedTracker @@ -259,6 +272,7 @@ func (f *ClientBuilder) Build() client.WithWatch { var result client.WithWatch = &fakeClient{ tracker: tracker, scheme: f.scheme, + clock: f.clock, restMapper: f.restMapper, indexes: f.indexes, withStatusSubresource: withStatusSubResource, @@ -1190,8 +1204,8 @@ func (sw *fakeSubResourceClient) Create(ctx context.Context, obj client.Object, return apierrors.NewNotFound(schema.GroupResource{}, "") } - tokenRequest.Status.Token = "fake-token" - tokenRequest.Status.ExpirationTimestamp = metav1.Date(6041, 1, 1, 0, 0, 0, 0, time.UTC) + tokenRequest.Status.Token = fmt.Sprintf("fake-token-%d", (ptr.Deref(tokenRequest.Spec.ExpirationSeconds, 3600))) + tokenRequest.Status.ExpirationTimestamp = metav1.Time{Time: sw.client.clock.Now().Add(time.Duration(ptr.Deref(tokenRequest.Spec.ExpirationSeconds, 3600)) * time.Second)} return sw.client.Get(ctx, client.ObjectKeyFromObject(obj), obj) default: diff --git a/pkg/client/fake/client_test.go b/pkg/client/fake/client_test.go index a23489756a..74805d233c 100644 --- a/pkg/client/fake/client_test.go +++ b/pkg/client/fake/client_test.go @@ -45,6 +45,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes/fake" + testclock "k8s.io/utils/clock/testing" "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" @@ -1964,14 +1965,38 @@ var _ = Describe("Fake client", func() { It("should create a ServiceAccount token through the token subresource", func() { sa := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "foo"}} - cl := NewClientBuilder().WithObjects(sa).Build() + fakeNow := time.Date(2021, 10, 4, 10, 0, 0, 0, time.UTC) + fakeClock := testclock.NewFakeClock(fakeNow) + + cl := NewClientBuilder().WithClock(fakeClock).WithObjects(sa).Build() + + tokenRequest := &authenticationv1.TokenRequest{ + Spec: authenticationv1.TokenRequestSpec{ + ExpirationSeconds: ptr.To[int64](600), + }, + } + err := cl.SubResource("token").Create(context.Background(), sa, tokenRequest) + Expect(err).NotTo(HaveOccurred()) + + Expect(tokenRequest.Status.Token).To(Equal("fake-token-600")) + expectedTimeStamp := metav1.NewTime(fakeNow.Add(600 * time.Second)) + Expect(tokenRequest.Status.ExpirationTimestamp).To(Equal(metav1.Time{Time: expectedTimeStamp.Time})) + }) + + It("should create a ServiceAccount token with default expiration if expirationSeconds is nil through the token subresource", func() { + sa := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "foo"}} + fakeNow := time.Date(2021, 10, 4, 10, 0, 0, 0, time.UTC) + fakeClock := testclock.NewFakeClock(fakeNow) + + cl := NewClientBuilder().WithClock(fakeClock).WithObjects(sa).Build() tokenRequest := &authenticationv1.TokenRequest{} err := cl.SubResource("token").Create(context.Background(), sa, tokenRequest) Expect(err).NotTo(HaveOccurred()) - Expect(tokenRequest.Status.Token).NotTo(Equal("")) - Expect(tokenRequest.Status.ExpirationTimestamp).NotTo(Equal(metav1.Time{})) + Expect(tokenRequest.Status.Token).To(Equal("fake-token-3600")) + expectedTimeStamp := metav1.NewTime(fakeNow.Add(3600 * time.Second)) + Expect(tokenRequest.Status.ExpirationTimestamp).To(Equal(metav1.Time{Time: expectedTimeStamp.Time})) }) It("should return not found when creating a token for a ServiceAccount that doesn't exist", func() {