Skip to content
This repository was archived by the owner on Dec 6, 2024. It is now read-only.

Commit 7875ce9

Browse files
committed
test: extended scaffolding
Signed-off-by: Mateusz Urbanek <[email protected]>
1 parent 73752e6 commit 7875ce9

File tree

7 files changed

+277
-101
lines changed

7 files changed

+277
-101
lines changed

Diff for: container-object-storage-interface-provisioner-sidecar/cmd/objectstorage-sidecar/cmd.go

+1-4
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,7 @@ func run(ctx context.Context, args []string) error {
9696
}
9797

9898
bl := bucket.NewBucketListener(info.Name, cosiClient)
99-
bal, err := bucketaccess.NewBucketAccessListener(info.Name, cosiClient)
100-
if err != nil {
101-
return err
102-
}
99+
bal := bucketaccess.NewBucketAccessListener(info.Name, cosiClient)
103100

104101
ctrl.AddBucketListener(bl)
105102
ctrl.AddBucketAccessListener(bal)

Diff for: container-object-storage-interface-provisioner-sidecar/pkg/bucket/bucket_controller.go

+9-19
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,12 @@ import (
2020
"fmt"
2121
"strings"
2222

23-
"github.com/pkg/errors"
2423
"google.golang.org/grpc/codes"
2524
"google.golang.org/grpc/status"
2625
v1 "k8s.io/api/core/v1"
2726
kubeerrors "k8s.io/apimachinery/pkg/api/errors"
2827
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2928
"k8s.io/apimachinery/pkg/runtime"
30-
utilversion "k8s.io/apimachinery/pkg/util/version"
3129
kube "k8s.io/client-go/kubernetes"
3230
"k8s.io/client-go/tools/record"
3331
"k8s.io/klog/v2"
@@ -49,7 +47,6 @@ type BucketListener struct {
4947

5048
kubeClient kube.Interface
5149
bucketClient buckets.Interface
52-
kubeVersion *utilversion.Version
5350
}
5451

5552
// NewBucketListener returns a resource handler for Bucket objects
@@ -76,8 +73,8 @@ func (b *BucketListener) Add(ctx context.Context, inputBucket *v1alpha1.Bucket)
7673
"name", bucket.ObjectMeta.Name)
7774

7875
if bucket.Spec.BucketClassName == "" {
79-
b.recordEvent(inputBucket, v1.EventTypeWarning, events.FailedCreateBucket, "BucketClassName was not defined in the Bucket %q.", bucket.Name)
80-
return errors.Wrapf(consts.ErrUndefinedBucketClassName, "Bucket %q", bucket.Name)
76+
b.recordEvent(inputBucket, v1.EventTypeWarning, events.FailedCreateBucket, "BucketClassName was not defined in the Bucket %v.", bucket.Name)
77+
return fmt.Errorf("%w for Bucket %v", consts.ErrUndefinedBucketClassName, bucket.Name)
8178
}
8279

8380
if !strings.EqualFold(bucket.Spec.DriverName, b.driverName) {
@@ -106,7 +103,7 @@ func (b *BucketListener) Add(ctx context.Context, inputBucket *v1alpha1.Bucket)
106103
if bucket.Spec.Parameters == nil {
107104
bucketClass, err := b.bucketClasses().Get(ctx, bucket.Spec.BucketClassName, metav1.GetOptions{})
108105
if kubeerrors.IsNotFound(err) {
109-
b.recordEvent(inputBucket, v1.EventTypeWarning, events.FailedCreateBucket, "BucketClass %q provided in the BucketClaim does not exist.", bucket.Spec.BucketClassName)
106+
b.recordEvent(inputBucket, v1.EventTypeWarning, events.FailedCreateBucket, err.Error())
110107
return err
111108
} else if err != nil {
112109
klog.V(3).ErrorS(err, "Error fetching bucketClass",
@@ -133,7 +130,7 @@ func (b *BucketListener) Add(ctx context.Context, inputBucket *v1alpha1.Bucket)
133130
rsp, err := b.provisionerClient.DriverCreateBucket(ctx, req)
134131
if err != nil {
135132
if status.Code(err) != codes.AlreadyExists {
136-
err = errors.Wrapf(err, "Failed to create Bucket %q", bucket.Name)
133+
err = fmt.Errorf("Failed to create Bucket %v: %w", bucket.Name, err)
137134
b.recordEvent(inputBucket, v1.EventTypeWarning, events.FailedCreateBucket, err.Error())
138135
return err
139136
}
@@ -143,7 +140,7 @@ func (b *BucketListener) Add(ctx context.Context, inputBucket *v1alpha1.Bucket)
143140
err = consts.ErrInternal
144141
klog.V(3).ErrorS(err, "Internal Error from driver",
145142
"bucket", bucket.ObjectMeta.Name)
146-
return errors.Wrapf(err, "Bucket %q", bucket.Name)
143+
return fmt.Errorf("%w for Bucket %v", err, bucket.Name)
147144
}
148145

149146
if rsp.BucketId != "" {
@@ -152,7 +149,7 @@ func (b *BucketListener) Add(ctx context.Context, inputBucket *v1alpha1.Bucket)
152149
} else {
153150
klog.V(3).ErrorS(err, "DriverCreateBucket returned an empty bucketID",
154151
"bucket", bucket.ObjectMeta.Name)
155-
return errors.Wrapf(consts.ErrEmptyBucketID, "Bucket %q", bucket.Name)
152+
return fmt.Errorf("%w for Bucket %v", consts.ErrEmptyBucketID, bucket.Name)
156153
}
157154

158155
// Now we update the BucketReady status of BucketClaim
@@ -181,7 +178,7 @@ func (b *BucketListener) Add(ctx context.Context, inputBucket *v1alpha1.Bucket)
181178
controllerutil.AddFinalizer(bucket, consts.BucketFinalizer)
182179
if bucket, err = b.buckets().Update(ctx, bucket, metav1.UpdateOptions{}); err != nil {
183180
klog.V(3).ErrorS(err, "Failed to update bucket finalizers", "bucket", bucket.ObjectMeta.Name)
184-
return errors.Wrap(err, "Failed to update bucket finalizers")
181+
return fmt.Errorf("failed to update bucket finalizers: %w", err)
185182
}
186183

187184
klog.V(5).Infof("Successfully added finalizer to bucket: %s", bucket.ObjectMeta.Name)
@@ -194,7 +191,7 @@ func (b *BucketListener) Add(ctx context.Context, inputBucket *v1alpha1.Bucket)
194191
if _, err = b.buckets().UpdateStatus(ctx, bucket, metav1.UpdateOptions{}); err != nil {
195192
klog.V(3).ErrorS(err, "Failed to update bucket status",
196193
"bucket", bucket.ObjectMeta.Name)
197-
return errors.Wrap(err, "Failed to update bucket status")
194+
return fmt.Errorf("failed to update bucket status: %w", err)
198195
}
199196

200197
klog.V(3).InfoS("Add Bucket success",
@@ -311,13 +308,6 @@ func (b *BucketListener) Delete(ctx context.Context, inputBucket *v1alpha1.Bucke
311308
// InitializeKubeClient initializes the kubernetes client
312309
func (b *BucketListener) InitializeKubeClient(k kube.Interface) {
313310
b.kubeClient = k
314-
315-
serverVersion, err := k.Discovery().ServerVersion()
316-
if err != nil {
317-
klog.V(3).ErrorS(err, "Cannot determine server version")
318-
} else {
319-
b.kubeVersion = utilversion.MustParseSemantic(serverVersion.GitVersion)
320-
}
321311
}
322312

323313
// InitializeBucketClient initializes the object storage bucket client
@@ -349,7 +339,7 @@ func (b *BucketListener) deleteBucketOp(ctx context.Context, bucket *v1alpha1.Bu
349339

350340
if _, err := b.provisionerClient.DriverDeleteBucket(ctx, req); err != nil {
351341
if status.Code(err) != codes.NotFound {
352-
b.recordEvent(bucket, v1.EventTypeWarning, events.FailedDeleteBucket, "Failed to delete bucket.")
342+
b.recordEvent(bucket, v1.EventTypeWarning, events.FailedDeleteBucket, err.Error())
353343
return err
354344
}
355345
}

Diff for: container-object-storage-interface-provisioner-sidecar/pkg/bucket/bucket_controller_test.go

+114-33
Original file line numberDiff line numberDiff line change
@@ -18,48 +18,31 @@ package bucket
1818
import (
1919
"context"
2020
"errors"
21-
"reflect"
21+
"fmt"
2222
"testing"
2323

24-
"sigs.k8s.io/container-object-storage-interface-api/apis/objectstorage/v1alpha1"
25-
fakebucketclientset "sigs.k8s.io/container-object-storage-interface-api/client/clientset/versioned/fake"
26-
cosi "sigs.k8s.io/container-object-storage-interface-spec"
27-
fakespec "sigs.k8s.io/container-object-storage-interface-spec/fake"
28-
24+
"google.golang.org/grpc"
25+
v1 "k8s.io/api/core/v1"
2926
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3027
"k8s.io/apimachinery/pkg/runtime"
31-
utilversion "k8s.io/apimachinery/pkg/util/version"
32-
"k8s.io/apimachinery/pkg/version"
33-
fakediscovery "k8s.io/client-go/discovery/fake"
3428
fakekubeclientset "k8s.io/client-go/kubernetes/fake"
3529
"k8s.io/client-go/tools/record"
36-
37-
"google.golang.org/grpc"
30+
"sigs.k8s.io/container-object-storage-interface-api/apis/objectstorage/v1alpha1"
31+
fakebucketclientset "sigs.k8s.io/container-object-storage-interface-api/client/clientset/versioned/fake"
32+
"sigs.k8s.io/container-object-storage-interface-api/controller/events"
33+
cosi "sigs.k8s.io/container-object-storage-interface-spec"
34+
fakespec "sigs.k8s.io/container-object-storage-interface-spec/fake"
3835
)
3936

4037
func TestInitializeKubeClient(t *testing.T) {
4138
client := fakekubeclientset.NewSimpleClientset()
42-
fakeDiscovery, ok := client.Discovery().(*fakediscovery.FakeDiscovery)
43-
if !ok {
44-
t.Fatalf("Couldn't convert Discovery() to *FakeDiscovery")
45-
}
46-
47-
fakeVersion := &version.Info{
48-
GitVersion: "v1.0.0",
49-
}
50-
fakeDiscovery.FakedServerVersion = fakeVersion
5139

5240
bl := BucketListener{}
5341
bl.InitializeKubeClient(client)
5442

5543
if bl.kubeClient == nil {
5644
t.Errorf("KubeClient was nil")
5745
}
58-
59-
expected := utilversion.MustParseSemantic(fakeVersion.GitVersion)
60-
if !reflect.DeepEqual(expected, bl.kubeVersion) {
61-
t.Errorf("Expected %+v, but got %+v", expected, bl.kubeVersion)
62-
}
6346
}
6447

6548
func TestInitializeBucketClient(t *testing.T) {
@@ -137,7 +120,7 @@ func TestMissingBucketClassName(t *testing.T) {
137120
}
138121
ctx := context.TODO()
139122
err := bl.Add(ctx, &b)
140-
expectedErr := errors.New("BucketClassName not defined for bucket testbucket")
123+
expectedErr := errors.New("BucketClassName not defined for Bucket testbucket")
141124
if err == nil || err.Error() != expectedErr.Error() {
142125
t.Errorf("Expecter error: %+v \n Returned error: %+v", expectedErr, err)
143126
}
@@ -149,18 +132,116 @@ func TestRecordEvents(t *testing.T) {
149132

150133
for _, tc := range []struct {
151134
name string
152-
expectedEvent struct {
153-
subject runtime.Object
154-
reason string
155-
message string
156-
}
157-
}{} {
135+
expectedEvent string
136+
cosiObjects []runtime.Object
137+
driver struct{ fakespec.FakeProvisionerClient }
138+
eventTrigger func(*testing.T, *BucketListener)
139+
}{
140+
{
141+
name: "",
142+
expectedEvent: newEvent(v1.EventTypeWarning, events.FailedCreateBucket, ""),
143+
eventTrigger: func(t *testing.T, bl *BucketListener) {
144+
panic("unimplemented")
145+
},
146+
driver: struct{ fakespec.FakeProvisionerClient }{
147+
FakeProvisionerClient: fakespec.FakeProvisionerClient{
148+
FakeDriverCreateBucket: func(
149+
_ context.Context,
150+
_ *cosi.DriverCreateBucketRequest,
151+
_ ...grpc.CallOption,
152+
) (*cosi.DriverCreateBucketResponse, error) {
153+
panic("unimplemented")
154+
},
155+
},
156+
},
157+
},
158+
{
159+
name: "",
160+
expectedEvent: newEvent(v1.EventTypeWarning, events.FailedCreateBucket, ""),
161+
eventTrigger: func(t *testing.T, bl *BucketListener) {
162+
panic("unimplemented")
163+
},
164+
driver: struct{ fakespec.FakeProvisionerClient }{
165+
FakeProvisionerClient: fakespec.FakeProvisionerClient{
166+
FakeDriverCreateBucket: func(
167+
_ context.Context,
168+
_ *cosi.DriverCreateBucketRequest,
169+
_ ...grpc.CallOption,
170+
) (*cosi.DriverCreateBucketResponse, error) {
171+
panic("unimplemented")
172+
},
173+
},
174+
},
175+
},
176+
{
177+
name: "",
178+
expectedEvent: newEvent(v1.EventTypeWarning, events.FailedCreateBucket, ""),
179+
eventTrigger: func(t *testing.T, bl *BucketListener) {
180+
panic("unimplemented")
181+
},
182+
driver: struct{ fakespec.FakeProvisionerClient }{
183+
FakeProvisionerClient: fakespec.FakeProvisionerClient{
184+
FakeDriverCreateBucket: func(
185+
_ context.Context,
186+
_ *cosi.DriverCreateBucketRequest,
187+
_ ...grpc.CallOption,
188+
) (*cosi.DriverCreateBucketResponse, error) {
189+
panic("unimplemented")
190+
},
191+
},
192+
},
193+
},
194+
{
195+
name: "",
196+
expectedEvent: newEvent(v1.EventTypeWarning, events.FailedDeleteBucket, ""),
197+
eventTrigger: func(t *testing.T, bl *BucketListener) {
198+
panic("unimplemented")
199+
},
200+
driver: struct{ fakespec.FakeProvisionerClient }{
201+
FakeProvisionerClient: fakespec.FakeProvisionerClient{
202+
FakeDriverDeleteBucket: func(
203+
_ context.Context,
204+
_ *cosi.DriverDeleteBucketRequest,
205+
_ ...grpc.CallOption,
206+
) (*cosi.DriverDeleteBucketResponse, error) {
207+
panic("unimplemented")
208+
},
209+
},
210+
},
211+
},
212+
} {
158213
tc := tc
159214

160215
t.Run(tc.name, func(t *testing.T) {
161216
t.Parallel()
162217

163-
// TODO: actual test
218+
client := fakebucketclientset.NewSimpleClientset(tc.cosiObjects...)
219+
kubeClient := fakekubeclientset.NewSimpleClientset()
220+
eventRecorder := record.NewFakeRecorder(1)
221+
222+
listener := NewBucketListener("test", &tc.driver)
223+
listener.InitializeKubeClient(kubeClient)
224+
listener.InitializeBucketClient(client)
225+
listener.InitializeEventRecorder(eventRecorder)
226+
227+
tc.eventTrigger(t, listener)
228+
229+
select {
230+
case event, ok := <-eventRecorder.Events:
231+
if ok {
232+
if event != tc.expectedEvent {
233+
t.Errorf("Expected %s \n got %s", tc.expectedEvent, event)
234+
}
235+
} else {
236+
t.Error("channel closed, no event")
237+
}
238+
default:
239+
t.Errorf("no event after trigger")
240+
}
164241
})
165242
}
166243
}
244+
245+
func newEvent(eventType, reason, message string) string {
246+
return fmt.Sprintf("%s %s %s", eventType, reason, message)
247+
}

Diff for: container-object-storage-interface-provisioner-sidecar/pkg/bucketaccess/bucketaccess_controller.go

+5-14
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import (
2929
kubeerrors "k8s.io/apimachinery/pkg/api/errors"
3030
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3131
"k8s.io/apimachinery/pkg/runtime"
32-
utilversion "k8s.io/apimachinery/pkg/util/version"
3332
kube "k8s.io/client-go/kubernetes"
3433
kubecorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
3534
"k8s.io/client-go/tools/record"
@@ -53,15 +52,14 @@ type BucketAccessListener struct {
5352

5453
kubeClient kube.Interface
5554
bucketClient buckets.Interface
56-
kubeVersion *utilversion.Version
5755
}
5856

5957
// NewBucketAccessListener returns a resource handler for BucketAccess objects
60-
func NewBucketAccessListener(driverName string, client cosi.ProvisionerClient) (*BucketAccessListener, error) {
58+
func NewBucketAccessListener(driverName string, client cosi.ProvisionerClient) *BucketAccessListener {
6159
return &BucketAccessListener{
6260
driverName: driverName,
6361
provisionerClient: client,
64-
}, nil
62+
}
6563
}
6664

6765
// Add attempts to provision credentials to access a given bucket. This function must be idempotent
@@ -96,7 +94,7 @@ func (bal *BucketAccessListener) Add(ctx context.Context, inputBucketAccess *v1a
9694

9795
bucketAccessClass, err := bal.bucketAccessClasses().Get(ctx, bucketAccessClassName, metav1.GetOptions{})
9896
if kubeerrors.IsNotFound(err) {
99-
bal.recordEvent(inputBucketAccess, v1.EventTypeWarning, events.FailedGrantAccess, "BucketAccessClass %q provided in the BucketAccess does not exist", bucketAccessClass.Name)
97+
bal.recordEvent(inputBucketAccess, v1.EventTypeWarning, events.FailedGrantAccess, "BucketAccessClass %v provided in the BucketAccess does not exist: %v", bucketAccessClass.Name, err)
10098
return err
10199
} else if err != nil {
102100
klog.ErrorS(err, "Failed to fetch bucketAccessClass", "bucketAccessClass", bucketAccessClassName)
@@ -136,7 +134,7 @@ func (bal *BucketAccessListener) Add(ctx context.Context, inputBucketAccess *v1a
136134
}
137135

138136
if authType == cosi.AuthenticationType_IAM && bucketAccess.Spec.ServiceAccountName == "" {
139-
bal.recordEvent(inputBucketAccess, v1.EventTypeWarning, events.FailedCreateBucket, "Must define ServiceAccountName when AuthenticationType is IAM.")
137+
bal.recordEvent(inputBucketAccess, v1.EventTypeWarning, events.FailedGrantAccess, "Must define ServiceAccountName when AuthenticationType is IAM.")
140138
return errors.New("Must define ServiceAccountName when AuthenticationType is IAM")
141139
}
142140

@@ -155,7 +153,7 @@ func (bal *BucketAccessListener) Add(ctx context.Context, inputBucketAccess *v1a
155153
}
156154

157155
if bucket.Status.BucketReady != true || bucket.Status.BucketID == "" {
158-
bal.recordEvent(inputBucketAccess, v1.EventTypeWarning, events.WaitingForBucket, "BucketAccess can't be granted to Bucket %q not in Ready state (isReady? %t) or without a bucketID (ID empty? %t).", bucket.Name, bucket.Status.BucketReady, bucket.Status.BucketID == "")
156+
bal.recordEvent(inputBucketAccess, v1.EventTypeWarning, events.WaitingForBucket, "BucketAccess can't be granted to Bucket %v not in Ready state (isReady? %t) or without a bucketID (ID empty? %t).", bucket.Name, bucket.Status.BucketReady, bucket.Status.BucketID == "")
159157
return consts.ErrInvalidBucketState
160158
}
161159

@@ -434,13 +432,6 @@ func (bal *BucketAccessListener) bucketAccessClasses() bucketapi.BucketAccessCla
434432
// InitializeKubeClient initializes the kubernetes client
435433
func (bal *BucketAccessListener) InitializeKubeClient(k kube.Interface) {
436434
bal.kubeClient = k
437-
438-
serverVersion, err := k.Discovery().ServerVersion()
439-
if err != nil {
440-
klog.V(3).ErrorS(err, "Cannot determine server version")
441-
} else {
442-
bal.kubeVersion = utilversion.MustParseSemantic(serverVersion.GitVersion)
443-
}
444435
}
445436

446437
// InitializeBucketClient initializes the object storage bucket client

0 commit comments

Comments
 (0)