Skip to content

Commit

Permalink
✨ Add fake.NewClientBuilder to build new fake clients
Browse files Browse the repository at this point in the history
This change allows us to iterate on the fake client without relying on
a small set of arguments passed to
NewFakeClient/NewFakeClientWithScheme.

The new builder accepts a variety of options to initialize the fake
client, including the scheme.

Because the builder seems more of a long term solution, I've marked the
older functions as deprecated in favor of NewClientBuilder.

Note: I dropped the "Fake" prefix given that it stutters with the
package name.

Signed-off-by: Vince Prignano <vincepri@vmware.com>
  • Loading branch information
vincepri committed Nov 30, 2020
1 parent 2879800 commit 6ffd8ac
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 11 deletions.
72 changes: 65 additions & 7 deletions pkg/client/fake/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,24 +59,82 @@ const (

// NewFakeClient creates a new fake client for testing.
// You can choose to initialize it with a slice of runtime.Object.
//
// Deprecated: Please use NewClientBuilder instead.
func NewFakeClient(initObjs ...runtime.Object) client.Client {
return NewFakeClientWithScheme(scheme.Scheme, initObjs...)
return NewClientBuilder().WithRuntimeObjects(initObjs...).Build()
}

// NewFakeClientWithScheme creates a new fake client with the given scheme
// for testing.
// You can choose to initialize it with a slice of runtime.Object.
//
// Deprecated: Please use NewClientBuilder instead.
func NewFakeClientWithScheme(clientScheme *runtime.Scheme, initObjs ...runtime.Object) client.Client {
tracker := testing.NewObjectTracker(clientScheme, scheme.Codecs.UniversalDecoder())
for _, obj := range initObjs {
err := tracker.Add(obj)
if err != nil {
return NewClientBuilder().WithScheme(clientScheme).WithRuntimeObjects(initObjs...).Build()
}

// NewClientBuilder returns a new builder to create a fake client.
func NewClientBuilder() *ClientBuilder {
return &ClientBuilder{
scheme: scheme.Scheme,
}
}

// ClientBuilder builds a fake client.
type ClientBuilder struct {
scheme *runtime.Scheme
initObject []client.Object
initLists []client.ObjectList
initRuntimeObjects []runtime.Object
}

// WithScheme sets this builder's internal scheme.
// If not set, defaults to client-go's global scheme.Scheme.
func (f *ClientBuilder) WithScheme(scheme *runtime.Scheme) *ClientBuilder {
f.scheme = scheme
return f
}

// WithObjects can be optionally used to initialize this fake client with client.Object(s).
func (f *ClientBuilder) WithObjects(initObjs ...client.Object) *ClientBuilder {
f.initObject = append(f.initObject, initObjs...)
return f
}

// WithObjects can be optionally used to initialize this fake client with client.ObjectList(s).
func (f *ClientBuilder) WithLists(initLists ...client.ObjectList) *ClientBuilder {
f.initLists = append(f.initLists, initLists...)
return f
}

// WithObjects can be optionally used to initialize this fake client with runtime.Object(s).
func (f *ClientBuilder) WithRuntimeObjects(initRuntimeObjs ...runtime.Object) *ClientBuilder {
f.initRuntimeObjects = append(f.initRuntimeObjects, initRuntimeObjs...)
return f
}

// Build builds and returns a new fake client.
func (f *ClientBuilder) Build() client.Client {
tracker := testing.NewObjectTracker(f.scheme, scheme.Codecs.UniversalDecoder())
for _, obj := range f.initObject {
if err := tracker.Add(obj); err != nil {
panic(fmt.Errorf("failed to add object %v to fake client: %w", obj, err))
}
}
for _, obj := range f.initLists {
if err := tracker.Add(obj); err != nil {
panic(fmt.Errorf("failed to add list %v to fake client: %w", obj, err))
}
}
for _, obj := range f.initRuntimeObjects {
if err := tracker.Add(obj); err != nil {
panic(fmt.Errorf("failed to add runtime object %v to fake client: %w", obj, err))
}
}
return &fakeClient{
tracker: versionedTracker{ObjectTracker: tracker, scheme: clientScheme},
scheme: clientScheme,
tracker: versionedTracker{ObjectTracker: tracker, scheme: f.scheme},
scheme: f.scheme,
}
}

Expand Down
10 changes: 8 additions & 2 deletions pkg/client/fake/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,9 @@ var _ = Describe("Fake client", func() {

Context("with default scheme.Scheme", func() {
BeforeEach(func(done Done) {
cl = NewFakeClient(dep, dep2, cm)
cl = NewClientBuilder().
WithObjects(dep, dep2, cm).
Build()
close(done)
})
AssertClientBehavior()
Expand All @@ -541,7 +543,11 @@ var _ = Describe("Fake client", func() {
Expect(corev1.AddToScheme(scheme)).To(Succeed())
Expect(appsv1.AddToScheme(scheme)).To(Succeed())
Expect(coordinationv1.AddToScheme(scheme)).To(Succeed())
cl = NewFakeClientWithScheme(scheme, &appsv1.DeploymentList{Items: []appsv1.Deployment{*dep, *dep2}}, cm)
cl = NewClientBuilder().
WithScheme(scheme).
WithObjects(cm).
WithLists(&appsv1.DeploymentList{Items: []appsv1.Deployment{*dep, *dep2}}).
Build()
close(done)
})
AssertClientBehavior()
Expand Down
4 changes: 2 additions & 2 deletions pkg/runtime/inject/inject_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ var _ = Describe("runtime inject", func() {
})

It("should set client", func() {
client, err := client.NewDelegatingClient(client.NewDelegatingClientInput{Client: fake.NewFakeClient()})
client, err := client.NewDelegatingClient(client.NewDelegatingClientInput{Client: fake.NewClientBuilder().Build()})
Expect(err).NotTo(HaveOccurred())

By("Validating injecting client")
Expand Down Expand Up @@ -153,7 +153,7 @@ var _ = Describe("runtime inject", func() {
})

It("should set api reader", func() {
apiReader, err := client.NewDelegatingClient(client.NewDelegatingClientInput{Client: fake.NewFakeClient()})
apiReader, err := client.NewDelegatingClient(client.NewDelegatingClientInput{Client: fake.NewClientBuilder().Build()})
Expect(err).NotTo(HaveOccurred())

By("Validating injecting client")
Expand Down

0 comments on commit 6ffd8ac

Please sign in to comment.