Skip to content

Commit bf5d641

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 bf5d641

8 files changed

Lines changed: 412 additions & 320 deletions

File tree

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ require (
88
github.com/go-logr/logr v1.2.0
99
github.com/go-logr/zapr v1.2.0
1010
github.com/onsi/ginkgo v1.16.5
11-
github.com/onsi/gomega v1.17.0
11+
github.com/onsi/gomega v1.18.1
1212
github.com/prometheus/client_golang v1.11.0
1313
github.com/prometheus/client_model v0.2.0
1414
go.uber.org/goleak v1.1.12
1515
go.uber.org/zap v1.19.1
16-
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8
16+
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
1717
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
1818
gomodules.xyz/jsonpatch/v2 v2.2.0
1919
k8s.io/api v0.23.0

go.sum

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
233233
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
234234
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
235235
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
236+
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
236237
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
237238
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
238239
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -353,11 +354,14 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k
353354
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
354355
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
355356
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
357+
github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ=
358+
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
356359
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
357360
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
358361
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
359-
github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
360362
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
363+
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
364+
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
361365
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
362366
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
363367
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
@@ -675,8 +679,8 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
675679
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
676680
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
677681
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
678-
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8 h1:M69LAlWZCshgp0QSzyDcSsSIejIEeuaCVpmwcKwyLMk=
679-
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
682+
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
683+
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
680684
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
681685
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
682686
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=

pkg/envtest/komega/default.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package komega
2+
3+
import (
4+
"sigs.k8s.io/controller-runtime/pkg/client"
5+
)
6+
7+
// defaultK is the Komega used by the package global functions.
8+
var defaultK = &komega{}
9+
10+
// SetDefaultClient sets the client used by the package global functions.
11+
func SetDefaultClient(c client.Client) {
12+
defaultK = &komega{client: c}
13+
}
14+
15+
func checkDefaultClient() {
16+
if defaultK.client == nil {
17+
panic("Default Komega's client is not set. Use WithDefaultClient to set it.")
18+
}
19+
}
20+
21+
// Get returns a function that fetches a resource and returns the occurring error.
22+
// It can be used with gomega.Eventually() like this
23+
// deployment := appsv1.Deployment{ ... }
24+
// gomega.Eventually(komega.Get(&deployment)).To(gomega.Succeed())
25+
// By calling the returned function directly it can also be used with gomega.Expect(komega.Get(...)()).To(...)
26+
func Get(obj client.Object) func() error {
27+
checkDefaultClient()
28+
return defaultK.Get(obj)
29+
}
30+
31+
// List returns a function that lists resources and returns the occurring error.
32+
// It can be used with gomega.Eventually() like this
33+
// deployments := v1.DeploymentList{ ... }
34+
// gomega.Eventually(k.List(&deployments)).To(gomega.Succeed())
35+
// By calling the returned function directly it can also be used as gomega.Expect(k.List(...)()).To(...)
36+
func List(obj client.ObjectList, opts ...client.ListOption) func() error {
37+
checkDefaultClient()
38+
return defaultK.List(obj, opts...)
39+
}
40+
41+
// Update returns a function that fetches a resource, applies the provided update function and then updates the resource.
42+
// It can be used with gomega.Eventually() like this:
43+
// deployment := appsv1.Deployment{ ... }
44+
// gomega.Eventually(k.Update(&deployment, func (o client.Object) {
45+
// deployment.Spec.Replicas = 3
46+
// return &deployment
47+
// })).To(gomega.Scucceed())
48+
// By calling the returned function directly it can also be used as gomega.Expect(k.Update(...)()).To(...)
49+
func Update(obj client.Object, f UpdateFunc, opts ...client.UpdateOption) func() error {
50+
checkDefaultClient()
51+
return defaultK.Update(obj, f, opts...)
52+
}
53+
54+
// UpdateStatus returns a function that fetches a resource, applies the provided update function and then updates the resource's status.
55+
// It can be used with gomega.Eventually() like this:
56+
// deployment := appsv1.Deployment{ ... }
57+
// gomega.Eventually(k.Update(&deployment, func (o client.Object) {
58+
// deployment.Status.AvailableReplicas = 1
59+
// return &deployment
60+
// })).To(gomega.Scucceed())
61+
// By calling the returned function directly it can also be used as gomega.Expect(k.UpdateStatus(...)()).To(...)
62+
func UpdateStatus(obj client.Object, f UpdateFunc, opts ...client.UpdateOption) func() error {
63+
checkDefaultClient()
64+
return defaultK.UpdateStatus(obj, f, opts...)
65+
}
66+
67+
// Object returns a function that fetches a resource and returns the object.
68+
// It can be used with gomega.Eventually() like this:
69+
// deployment := appsv1.Deployment{ ... }
70+
// gomega.Eventually(k.Object(&deployment)).To(HaveField("Spec.Replicas", gomega.Equal(pointer.Int32(3))))
71+
// By calling the returned function directly it can also be used as gomega.Expect(k.Object(...)()).To(...)
72+
func Object(obj client.Object) func() (client.Object, error) {
73+
checkDefaultClient()
74+
return defaultK.Object(obj)
75+
}
76+
77+
// ObjectList returns a function that fetches a resource and returns the object.
78+
// It can be used with gomega.Eventually() like this:
79+
// deployments := appsv1.DeploymentList{ ... }
80+
// gomega.Eventually(k.ObjectList(&deployments)).To(HaveField("Items", HaveLen(1)))
81+
// By calling the returned function directly it can also be used as gomega.Expect(k.ObjectList(...)()).To(...)
82+
func ObjectList(obj client.ObjectList, opts ...client.ListOption) func() (client.ObjectList, error) {
83+
checkDefaultClient()
84+
return defaultK.ObjectList(obj, opts...)
85+
}

pkg/envtest/komega/interfaces.go

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,41 +18,65 @@ 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 returns a function that fetches a resource and returns the occurring error.
28+
// It can be used with gomega.Eventually() like this
29+
// deployment := appsv1.Deployment{ ... }
30+
// gomega.Eventually(k.Get(&deployment)).To(gomega.Succeed())
31+
// By calling the returned function directly it can also be used with gomega.Expect(k.Get(...)()).To(...)
32+
Get(client.Object) func() error
3433

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-
}
34+
// List returns a function that lists resources and returns the occurring error.
35+
// It can be used with gomega.Eventually() like this
36+
// deployments := v1.DeploymentList{ ... }
37+
// gomega.Eventually(k.List(&deployments)).To(gomega.Succeed())
38+
// By calling the returned function directly it can also be used as gomega.Expect(k.List(...)()).To(...)
39+
List(client.ObjectList, ...client.ListOption) func() error
40+
41+
// Update returns a function that fetches a resource, applies the provided update function and then updates the resource.
42+
// It can be used with gomega.Eventually() like this:
43+
// deployment := appsv1.Deployment{ ... }
44+
// gomega.Eventually(k.Update(&deployment, func (o client.Object) {
45+
// deployment.Spec.Replicas = 3
46+
// return &deployment
47+
// })).To(gomega.Scucceed())
48+
// By calling the returned function directly it can also be used as gomega.Expect(k.Update(...)()).To(...)
49+
Update(client.Object, UpdateFunc, ...client.UpdateOption) func() error
4250

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
51+
// UpdateStatus returns a function that fetches a resource, applies the provided update function and then updates the resource's status.
52+
// It can be used with gomega.Eventually() like this:
53+
// deployment := appsv1.Deployment{ ... }
54+
// gomega.Eventually(k.Update(&deployment, func (o client.Object) {
55+
// deployment.Status.AvailableReplicas = 1
56+
// return &deployment
57+
// })).To(gomega.Scucceed())
58+
// By calling the returned function directly it can also be used as gomega.Expect(k.UpdateStatus(...)()).To(...)
59+
UpdateStatus(client.Object, UpdateFunc, ...client.UpdateOption) func() error
60+
61+
// Object returns a function that fetches a resource and returns the object.
62+
// It can be used with gomega.Eventually() like this:
63+
// deployment := appsv1.Deployment{ ... }
64+
// gomega.Eventually(k.Object(&deployment)).To(HaveField("Spec.Replicas", gomega.Equal(pointer.Int32(3))))
65+
// By calling the returned function directly it can also be used as gomega.Expect(k.Object(...)()).To(...)
66+
Object(client.Object) func() (client.Object, error)
67+
68+
// ObjectList returns a function that fetches a resource and returns the object.
69+
// It can be used with gomega.Eventually() like this:
70+
// deployments := appsv1.DeploymentList{ ... }
71+
// gomega.Eventually(k.ObjectList(&deployments)).To(HaveField("Items", HaveLen(1)))
72+
// By calling the returned function directly it can also be used as gomega.Expect(k.ObjectList(...)()).To(...)
73+
ObjectList(client.ObjectList, ...client.ListOption) func() (client.ObjectList, error)
74+
75+
// WithClient returns a copy that uses the given client.
76+
WithClient(client.Client) Komega
77+
// WithContext returns a copy that uses the given context.
78+
WithContext(context.Context) Komega
5479
}
5580

56-
// UpdateFunc modifies the object fetched from the API server before sending
57-
// the update
81+
// UpdateFunc receives an object and expects a modified version of it to be returned.
5882
type UpdateFunc func(client.Object) client.Object

pkg/envtest/komega/komega.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
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 is a collection of utilites for writing tests involving a mocked
27+
// Kubernetes API.
28+
type komega struct {
29+
ctx context.Context
30+
client client.Client
31+
}
32+
33+
var _ Komega = &komega{}
34+
35+
// New creates a new Komega instance with the given client.
36+
func New(c client.Client) Komega {
37+
return &komega{
38+
client: c,
39+
}
40+
}
41+
42+
// WithContext returns a copy that uses the given context.
43+
func (k komega) WithContext(ctx context.Context) Komega {
44+
k.ctx = ctx
45+
return &k
46+
}
47+
48+
// WithClient returns a copy that uses the given client.
49+
func (k komega) WithClient(c client.Client) Komega {
50+
k.client = c
51+
return &k
52+
}
53+
54+
// context returns the matcher context if one has been set or context.Background() otherwise.
55+
func (k *komega) context() context.Context {
56+
if k.ctx == nil {
57+
return context.Background()
58+
}
59+
return k.ctx
60+
}
61+
62+
// Get returns a function that fetches a resource and returns the occurring error.
63+
func (k *komega) Get(obj client.Object) func() error {
64+
key := types.NamespacedName{
65+
Name: obj.GetName(),
66+
Namespace: obj.GetNamespace(),
67+
}
68+
return func() error {
69+
return k.client.Get(k.context(), key, obj)
70+
}
71+
}
72+
73+
// List returns a function that lists resources and returns the occurring error.
74+
func (k *komega) List(obj client.ObjectList, opts ...client.ListOption) func() error {
75+
return func() error {
76+
return k.client.List(k.context(), obj, opts...)
77+
}
78+
}
79+
80+
// Update returns a function that fetches a resource, applies the provided update function and then updates the resource.
81+
func (k *komega) Update(obj client.Object, updateFunc UpdateFunc, opts ...client.UpdateOption) func() error {
82+
key := types.NamespacedName{
83+
Name: obj.GetName(),
84+
Namespace: obj.GetNamespace(),
85+
}
86+
return func() error {
87+
err := k.client.Get(k.context(), key, obj)
88+
if err != nil {
89+
return err
90+
}
91+
return k.client.Update(k.context(), updateFunc(obj), opts...)
92+
}
93+
}
94+
95+
// UpdateStatus returns a function that fetches a resource, applies the provided update function and then updates the resource's status.
96+
func (k *komega) UpdateStatus(obj client.Object, updateFunc UpdateFunc, opts ...client.UpdateOption) func() error {
97+
key := types.NamespacedName{
98+
Name: obj.GetName(),
99+
Namespace: obj.GetNamespace(),
100+
}
101+
return func() error {
102+
err := k.client.Get(k.context(), key, obj)
103+
if err != nil {
104+
return err
105+
}
106+
return k.client.Status().Update(k.context(), updateFunc(obj), opts...)
107+
}
108+
}
109+
110+
// Object returns a function that fetches a resource and returns the object.
111+
func (k *komega) Object(obj client.Object) func() (client.Object, error) {
112+
key := types.NamespacedName{
113+
Name: obj.GetName(),
114+
Namespace: obj.GetNamespace(),
115+
}
116+
return func() (client.Object, error) {
117+
err := k.client.Get(k.context(), key, obj)
118+
return obj, err
119+
}
120+
}
121+
122+
// ObjectList returns a function that fetches a resource and returns the object.
123+
func (k *komega) ObjectList(obj client.ObjectList, opts ...client.ListOption) func() (client.ObjectList, error) {
124+
return func() (client.ObjectList, error) {
125+
err := k.client.List(k.context(), obj, opts...)
126+
return obj, err
127+
}
128+
}

0 commit comments

Comments
 (0)