Skip to content

Commit 81ce7c3

Browse files
trgeigerclaude
andcommitted
Add clustercatalog_controller unit tests
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent c3ea325 commit 81ce7c3

File tree

8 files changed

+2173
-4
lines changed

8 files changed

+2173
-4
lines changed

pkg/controllers/clustercatalog_controller.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package controllers
22

33
import (
44
"context"
5+
"fmt"
56

67
"github.com/openshift/console/pkg/olm"
78
ocv1 "github.com/operator-framework/operator-controller/api/v1"
@@ -53,15 +54,13 @@ func (r *ClusterCatalogReconciler) Reconcile(ctx context.Context, req reconcile.
5354

5455
// The ClusterCatalog has been found on the cluster, attempt to add to or update cache
5556
if clusterCatalog.Status.URLs == nil {
56-
klog.Error("ClusterCatalog URLs field is empty", "name", req.Name)
57-
return ctrl.Result{}, nil
57+
return ctrl.Result{}, fmt.Errorf("URLs field is empty for clustercatalog %s", req.Name)
5858
}
5959

6060
baseURL := clusterCatalog.Status.URLs.Base
6161

6262
if baseURL == "" {
63-
klog.Error("ClusterCatalog Base URL is empty", "name", req.Name)
64-
return ctrl.Result{}, nil
63+
return ctrl.Result{}, fmt.Errorf("base URL is empty for clustercatalog %s", req.Name)
6564
}
6665

6766
err = r.catalogService.UpdateCatalog(req.Name, baseURL)
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
package controllers
2+
3+
import (
4+
"context"
5+
"errors"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
ocv1 "github.com/operator-framework/operator-controller/api/v1"
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/apimachinery/pkg/runtime"
13+
"k8s.io/apimachinery/pkg/types"
14+
"sigs.k8s.io/controller-runtime/pkg/client"
15+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
16+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
17+
)
18+
19+
type mockCatalogService struct {
20+
updateCatalogCalled bool
21+
removeCatalogCalled bool
22+
updateError error
23+
removeError error
24+
lastCatalogName string
25+
lastBaseURL string
26+
}
27+
28+
func (m *mockCatalogService) UpdateCatalog(catalogName string, baseURL string) error {
29+
m.updateCatalogCalled = true
30+
m.lastCatalogName = catalogName
31+
m.lastBaseURL = baseURL
32+
return m.updateError
33+
}
34+
35+
func (m *mockCatalogService) RemoveCatalog(catalogName string) error {
36+
m.removeCatalogCalled = true
37+
m.lastCatalogName = catalogName
38+
return m.removeError
39+
}
40+
41+
func createTestReconciler(objects ...client.Object) (*ClusterCatalogReconciler, *mockCatalogService) {
42+
scheme := runtime.NewScheme()
43+
_ = ocv1.AddToScheme(scheme)
44+
45+
fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(objects...).Build()
46+
mockService := &mockCatalogService{}
47+
48+
return &ClusterCatalogReconciler{
49+
Client: fakeClient,
50+
Scheme: scheme,
51+
catalogService: mockService,
52+
}, mockService
53+
}
54+
55+
func TestReconcile_ClusterCatalogNotFound(t *testing.T) {
56+
reconciler, mockService := createTestReconciler()
57+
58+
req := reconcile.Request{
59+
NamespacedName: types.NamespacedName{
60+
Name: "test-catalog",
61+
},
62+
}
63+
64+
result, err := reconciler.Reconcile(context.Background(), req)
65+
66+
require.NoError(t, err)
67+
assert.Equal(t, reconcile.Result{}, result)
68+
assert.True(t, mockService.removeCatalogCalled)
69+
assert.Equal(t, "test-catalog", mockService.lastCatalogName)
70+
}
71+
72+
func TestReconcile_ClusterCatalogNoURLs(t *testing.T) {
73+
clusterCatalog := &ocv1.ClusterCatalog{
74+
ObjectMeta: metav1.ObjectMeta{
75+
Name: "test-catalog",
76+
},
77+
Status: ocv1.ClusterCatalogStatus{
78+
URLs: nil,
79+
},
80+
}
81+
82+
reconciler, mockService := createTestReconciler(clusterCatalog)
83+
84+
req := reconcile.Request{
85+
NamespacedName: types.NamespacedName{
86+
Name: "test-catalog",
87+
},
88+
}
89+
90+
result, err := reconciler.Reconcile(context.Background(), req)
91+
92+
require.Error(t, err)
93+
assert.Equal(t, "URLs field is empty for clustercatalog test-catalog", err.Error())
94+
assert.Equal(t, reconcile.Result{}, result)
95+
assert.False(t, mockService.updateCatalogCalled)
96+
assert.False(t, mockService.removeCatalogCalled)
97+
}
98+
99+
func TestReconcile_ClusterCatalogEmptyBaseURL(t *testing.T) {
100+
clusterCatalog := &ocv1.ClusterCatalog{
101+
ObjectMeta: metav1.ObjectMeta{
102+
Name: "test-catalog",
103+
},
104+
Status: ocv1.ClusterCatalogStatus{
105+
URLs: &ocv1.ClusterCatalogURLs{
106+
Base: "",
107+
},
108+
},
109+
}
110+
111+
reconciler, mockService := createTestReconciler(clusterCatalog)
112+
113+
req := reconcile.Request{
114+
NamespacedName: types.NamespacedName{
115+
Name: "test-catalog",
116+
},
117+
}
118+
119+
result, err := reconciler.Reconcile(context.Background(), req)
120+
121+
require.Error(t, err)
122+
assert.Equal(t, "base URL is empty for clustercatalog test-catalog", err.Error())
123+
assert.Equal(t, reconcile.Result{}, result)
124+
assert.False(t, mockService.updateCatalogCalled)
125+
assert.False(t, mockService.removeCatalogCalled)
126+
}
127+
128+
func TestReconcile_ClusterCatalogSuccess(t *testing.T) {
129+
clusterCatalog := &ocv1.ClusterCatalog{
130+
ObjectMeta: metav1.ObjectMeta{
131+
Name: "test-catalog",
132+
},
133+
Status: ocv1.ClusterCatalogStatus{
134+
URLs: &ocv1.ClusterCatalogURLs{
135+
Base: "https://example.com/catalog",
136+
},
137+
},
138+
}
139+
140+
reconciler, mockService := createTestReconciler(clusterCatalog)
141+
142+
req := reconcile.Request{
143+
NamespacedName: types.NamespacedName{
144+
Name: "test-catalog",
145+
},
146+
}
147+
148+
result, err := reconciler.Reconcile(context.Background(), req)
149+
150+
require.NoError(t, err)
151+
assert.Equal(t, reconcile.Result{}, result)
152+
assert.True(t, mockService.updateCatalogCalled)
153+
assert.Equal(t, "test-catalog", mockService.lastCatalogName)
154+
assert.Equal(t, "https://example.com/catalog", mockService.lastBaseURL)
155+
}
156+
157+
func TestReconcile_UpdateCatalogError(t *testing.T) {
158+
clusterCatalog := &ocv1.ClusterCatalog{
159+
ObjectMeta: metav1.ObjectMeta{
160+
Name: "test-catalog",
161+
},
162+
Status: ocv1.ClusterCatalogStatus{
163+
URLs: &ocv1.ClusterCatalogURLs{
164+
Base: "https://example.com/catalog",
165+
},
166+
},
167+
}
168+
169+
reconciler, mockService := createTestReconciler(clusterCatalog)
170+
mockService.updateError = errors.New("update failed")
171+
172+
req := reconcile.Request{
173+
NamespacedName: types.NamespacedName{
174+
Name: "test-catalog",
175+
},
176+
}
177+
178+
result, err := reconciler.Reconcile(context.Background(), req)
179+
180+
require.Error(t, err)
181+
assert.Equal(t, reconcile.Result{}, result)
182+
assert.True(t, mockService.updateCatalogCalled)
183+
}
184+
185+
func TestReconcile_RemoveCatalogError(t *testing.T) {
186+
reconciler, mockService := createTestReconciler()
187+
mockService.removeError = errors.New("remove failed")
188+
189+
req := reconcile.Request{
190+
NamespacedName: types.NamespacedName{
191+
Name: "test-catalog",
192+
},
193+
}
194+
195+
result, err := reconciler.Reconcile(context.Background(), req)
196+
197+
require.Error(t, err)
198+
assert.Equal(t, reconcile.Result{}, result)
199+
assert.True(t, mockService.removeCatalogCalled)
200+
}

vendor/k8s.io/apimachinery/pkg/util/rand/rand.go

Lines changed: 127 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/modules.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,7 @@ k8s.io/apimachinery/pkg/util/naming
12331233
k8s.io/apimachinery/pkg/util/net
12341234
k8s.io/apimachinery/pkg/util/portforward
12351235
k8s.io/apimachinery/pkg/util/proxy
1236+
k8s.io/apimachinery/pkg/util/rand
12361237
k8s.io/apimachinery/pkg/util/remotecommand
12371238
k8s.io/apimachinery/pkg/util/runtime
12381239
k8s.io/apimachinery/pkg/util/sets
@@ -1720,6 +1721,8 @@ sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics
17201721
sigs.k8s.io/controller-runtime/pkg/client
17211722
sigs.k8s.io/controller-runtime/pkg/client/apiutil
17221723
sigs.k8s.io/controller-runtime/pkg/client/config
1724+
sigs.k8s.io/controller-runtime/pkg/client/fake
1725+
sigs.k8s.io/controller-runtime/pkg/client/interceptor
17231726
sigs.k8s.io/controller-runtime/pkg/cluster
17241727
sigs.k8s.io/controller-runtime/pkg/config
17251728
sigs.k8s.io/controller-runtime/pkg/controller
@@ -1735,6 +1738,7 @@ sigs.k8s.io/controller-runtime/pkg/internal/field/selector
17351738
sigs.k8s.io/controller-runtime/pkg/internal/httpserver
17361739
sigs.k8s.io/controller-runtime/pkg/internal/log
17371740
sigs.k8s.io/controller-runtime/pkg/internal/metrics
1741+
sigs.k8s.io/controller-runtime/pkg/internal/objectutil
17381742
sigs.k8s.io/controller-runtime/pkg/internal/recorder
17391743
sigs.k8s.io/controller-runtime/pkg/internal/source
17401744
sigs.k8s.io/controller-runtime/pkg/internal/syncs

0 commit comments

Comments
 (0)