Skip to content

Commit e91169f

Browse files
committed
refactor komega package
rename Matcher to komega since it's not really a matcher komega.With... methods now return copies allow to specify a Gomega instance to use
1 parent c472f24 commit e91169f

File tree

5 files changed

+281
-266
lines changed

5 files changed

+281
-266
lines changed

pkg/envtest/komega/interfaces.go

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,39 +18,22 @@ package komega
1818

1919
import (
2020
"context"
21-
"time"
2221

23-
"github.com/onsi/gomega"
24-
"k8s.io/apimachinery/pkg/runtime"
2522
"sigs.k8s.io/controller-runtime/pkg/client"
2623
)
2724

2825
// Komega is the root interface that the Matcher implements.
2926
type Komega interface {
30-
KomegaAsync
31-
KomegaSync
32-
WithContext(context.Context) Komega
33-
}
27+
Get(client.Object) func() error
28+
List(client.ObjectList, ...client.ListOption) func() error
29+
Update(client.Object, UpdateFunc, ...client.UpdateOption) func() error
30+
UpdateStatus(client.Object, UpdateFunc, ...client.UpdateOption) func() error
3431

35-
// KomegaSync is the interface for any sync assertions that
36-
// the matcher implements.
37-
type KomegaSync interface {
38-
Create(client.Object, ...client.CreateOption) gomega.GomegaAssertion
39-
Delete(client.Object, ...client.DeleteOption) gomega.GomegaAssertion
40-
WithExtras(...interface{}) KomegaSync
41-
}
32+
Object(client.Object) func() client.Object
33+
ObjectList(client.ObjectList, ...client.ListOption) func() client.ObjectList
4234

43-
// KomegaAsync is the interface for any async assertions that
44-
// the matcher implements.
45-
type KomegaAsync interface {
46-
Consistently(runtime.Object, ...client.ListOption) gomega.AsyncAssertion
47-
Eventually(runtime.Object, ...client.ListOption) gomega.AsyncAssertion
48-
Get(client.Object) gomega.AsyncAssertion
49-
List(client.ObjectList, ...client.ListOption) gomega.AsyncAssertion
50-
Update(client.Object, UpdateFunc, ...client.UpdateOption) gomega.AsyncAssertion
51-
UpdateStatus(client.Object, UpdateFunc, ...client.UpdateOption) gomega.AsyncAssertion
52-
WithTimeout(time.Duration) KomegaAsync
53-
WithPollInterval(time.Duration) KomegaAsync
35+
WithClient(client.Client) Komega
36+
WithContext(context.Context) Komega
5437
}
5538

5639
// UpdateFunc modifies the object fetched from the API server before sending

pkg/envtest/komega/komega.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
Copyright 2021 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package komega
18+
19+
import (
20+
"context"
21+
22+
"k8s.io/apimachinery/pkg/types"
23+
"sigs.k8s.io/controller-runtime/pkg/client"
24+
)
25+
26+
// komega has Gomega Matchers that use the controller-runtime client.
27+
type komega struct {
28+
ctx context.Context
29+
client client.Client
30+
}
31+
32+
var _ Komega = &komega{}
33+
34+
// NewKomega creates a new instance with a given client.
35+
func NewKomega(c client.Client) Komega {
36+
return &komega{
37+
client: c,
38+
}
39+
}
40+
41+
// WithContext returns a copy using the given Context.
42+
func (k komega) WithContext(ctx context.Context) Komega {
43+
k.ctx = ctx
44+
return &k
45+
}
46+
47+
func (k komega) WithClient(c client.Client) Komega {
48+
k.client = c
49+
return &k
50+
}
51+
52+
// context returns the matcher context if one has been set.
53+
// Else it returns the context.TODO().
54+
func (k *komega) context() context.Context {
55+
if k.ctx == nil {
56+
return context.Background()
57+
}
58+
return k.ctx
59+
}
60+
61+
// Get fetches an object until the forwarded error matches.
62+
func (k *komega) Get(obj client.Object) func() error {
63+
key := types.NamespacedName{
64+
Name: obj.GetName(),
65+
Namespace: obj.GetNamespace(),
66+
}
67+
return func() error {
68+
return k.client.Get(k.context(), key, obj)
69+
}
70+
}
71+
72+
// List returns a function that
73+
func (k *komega) List(obj client.ObjectList, opts ...client.ListOption) func() error {
74+
return func() error {
75+
return k.client.List(k.context(), obj, opts...)
76+
}
77+
}
78+
79+
// Update tries to update an object by applying the updateFunc until the forwarded error matches.
80+
func (k *komega) Update(obj client.Object, updateFunc UpdateFunc, opts ...client.UpdateOption) func() error {
81+
key := types.NamespacedName{
82+
Name: obj.GetName(),
83+
Namespace: obj.GetNamespace(),
84+
}
85+
return func() error {
86+
err := k.client.Get(k.context(), key, obj)
87+
if err != nil {
88+
return err
89+
}
90+
return k.client.Update(k.context(), updateFunc(obj), opts...)
91+
}
92+
}
93+
94+
// UpdateStatus tries to update an object's status by applying the updateFunc until the forwarded error matches.
95+
func (k *komega) UpdateStatus(obj client.Object, updateFunc UpdateFunc, opts ...client.UpdateOption) func() error {
96+
key := types.NamespacedName{
97+
Name: obj.GetName(),
98+
Namespace: obj.GetNamespace(),
99+
}
100+
return func() error {
101+
err := k.client.Get(k.context(), key, obj)
102+
if err != nil {
103+
return err
104+
}
105+
return k.client.Status().Update(k.context(), updateFunc(obj), opts...)
106+
}
107+
}
108+
109+
// consistentlyclient.Object gets an individual object from the API server.
110+
func (k *komega) Object(obj client.Object) func() client.Object {
111+
key := types.NamespacedName{
112+
Name: obj.GetName(),
113+
Namespace: obj.GetNamespace(),
114+
}
115+
return func() client.Object {
116+
err := k.client.Get(k.context(), key, obj)
117+
if err != nil {
118+
panic(err)
119+
}
120+
return obj
121+
}
122+
}
123+
124+
// consistentlyList gets an list of objects from the API server.
125+
func (k *komega) ObjectList(obj client.ObjectList, opts ...client.ListOption) func() client.ObjectList {
126+
return func() client.ObjectList {
127+
err := k.client.List(k.context(), obj, opts...)
128+
if err != nil {
129+
panic(err)
130+
}
131+
return obj
132+
}
133+
}

pkg/envtest/komega/komega_test.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package komega
2+
3+
import (
4+
"testing"
5+
6+
gomega "github.com/onsi/gomega"
7+
appsv1 "k8s.io/api/apps/v1"
8+
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
"k8s.io/utils/pointer"
10+
11+
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
12+
)
13+
14+
func TestGet(t *testing.T) {
15+
g := gomega.NewWithT(t)
16+
17+
deployment := appsv1.Deployment{
18+
ObjectMeta: v1.ObjectMeta{
19+
Namespace: "default",
20+
Name: "test",
21+
},
22+
Spec: appsv1.DeploymentSpec{
23+
Replicas: pointer.Int32(5),
24+
},
25+
}
26+
27+
fc := fakeclient.NewClientBuilder().
28+
WithObjects(&deployment).
29+
Build()
30+
31+
k := NewKomega(fc)
32+
33+
fetched := appsv1.Deployment{
34+
ObjectMeta: v1.ObjectMeta{
35+
Namespace: "default",
36+
Name: "test",
37+
},
38+
}
39+
g.Eventually(k.Get(&fetched)).Should(gomega.Succeed())
40+
41+
g.Expect(*fetched.Spec.Replicas).To(gomega.BeEquivalentTo(5))
42+
}
43+
44+
func TestList(t *testing.T) {
45+
g := gomega.NewWithT(t)
46+
47+
deployment := appsv1.Deployment{
48+
ObjectMeta: v1.ObjectMeta{
49+
Namespace: "default",
50+
Name: "test",
51+
},
52+
}
53+
54+
fc := fakeclient.NewClientBuilder().
55+
WithObjects(&deployment).
56+
Build()
57+
58+
k := NewKomega(fc)
59+
60+
list := appsv1.DeploymentList{}
61+
g.Eventually(k.List(&list)).Should(gomega.Succeed())
62+
63+
g.Expect(list.Items).To(gomega.HaveLen(1))
64+
g.Expect(list.Items[0]).To(gomega.Equal(deployment))
65+
}
66+
67+
func TestUpdate(t *testing.T) {
68+
69+
}
70+
71+
func TestUpdateStatus(t *testing.T) {
72+
73+
}
74+
75+
func TestObject(t *testing.T) {
76+
g := gomega.NewWithT(t)
77+
78+
deployment := appsv1.Deployment{
79+
ObjectMeta: v1.ObjectMeta{
80+
Namespace: "default",
81+
Name: "test",
82+
},
83+
Spec: appsv1.DeploymentSpec{
84+
Replicas: pointer.Int32(5),
85+
},
86+
}
87+
88+
fc := fakeclient.NewClientBuilder().
89+
WithObjects(&deployment).
90+
Build()
91+
92+
k := NewKomega(fc)
93+
94+
fetched := appsv1.Deployment{
95+
ObjectMeta: v1.ObjectMeta{
96+
Namespace: "default",
97+
Name: "test",
98+
},
99+
}
100+
g.Eventually(k.Object(&fetched)).Should(gomega.And(
101+
gomega.Not(gomega.BeNil()),
102+
HaveField("Spec.Replicas", gomega.Equal(pointer.Int32(5))),
103+
))
104+
}
105+
106+
func TestObjectList(t *testing.T) {
107+
g := gomega.NewWithT(t)
108+
109+
deployment := appsv1.Deployment{
110+
ObjectMeta: v1.ObjectMeta{
111+
Namespace: "default",
112+
Name: "test",
113+
},
114+
Spec: appsv1.DeploymentSpec{
115+
Replicas: pointer.Int32(5),
116+
},
117+
}
118+
119+
fc := fakeclient.NewClientBuilder().
120+
WithObjects(&deployment).
121+
Build()
122+
123+
k := NewKomega(fc)
124+
125+
list := appsv1.DeploymentList{}
126+
g.Eventually(k.ObjectList(&list)).Should(gomega.And(
127+
gomega.Not(gomega.BeNil()),
128+
HaveField("Items", gomega.And(
129+
gomega.HaveLen(1),
130+
gomega.ContainElement(WithField("Spec.Replicas", gomega.Equal(pointer.Int32(5)))),
131+
)),
132+
))
133+
}

0 commit comments

Comments
 (0)