Skip to content

Commit 9fbbdbf

Browse files
committed
test: add table-driven tests for PullSecrets with edge case coverage
Signed-off-by: Rohan Kumar <[email protected]>
1 parent 09765a5 commit 9fbbdbf

File tree

1 file changed

+192
-0
lines changed

1 file changed

+192
-0
lines changed
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
package workspace
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/devfile/devworkspace-operator/pkg/dwerrors"
8+
"github.com/devfile/devworkspace-operator/pkg/infrastructure"
9+
"github.com/devfile/devworkspace-operator/pkg/provision/sync"
10+
"k8s.io/apimachinery/pkg/runtime"
11+
"sigs.k8s.io/controller-runtime/pkg/client"
12+
13+
"github.com/devfile/devworkspace-operator/pkg/constants"
14+
corev1 "k8s.io/api/core/v1"
15+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
17+
18+
"github.com/stretchr/testify/assert"
19+
)
20+
21+
func TestPullSecrets_TableDriven(t *testing.T) {
22+
namespace := "test-ns"
23+
serviceAccountName := "test-sa"
24+
25+
tests := []struct {
26+
name string
27+
objects []client.Object
28+
setupInfra func()
29+
expectedError error
30+
expectedSecrets []string // expected PullSecret names
31+
}{
32+
{
33+
name: "ServiceAccount not found",
34+
objects: []client.Object{}, // No SA created
35+
setupInfra: func() {
36+
infrastructure.InitializeForTesting(infrastructure.Kubernetes)
37+
},
38+
expectedError: nil,
39+
expectedSecrets: []string{},
40+
},
41+
{
42+
name: "Secret with incorrect type is skipped",
43+
objects: []client.Object{
44+
&corev1.ServiceAccount{
45+
TypeMeta: metav1.TypeMeta{
46+
Kind: "ServiceAccount",
47+
APIVersion: corev1.SchemeGroupVersion.String(),
48+
},
49+
ObjectMeta: metav1.ObjectMeta{
50+
Name: serviceAccountName,
51+
Namespace: namespace,
52+
},
53+
},
54+
&corev1.Secret{
55+
TypeMeta: metav1.TypeMeta{
56+
Kind: "Secret",
57+
APIVersion: corev1.SchemeGroupVersion.String(),
58+
},
59+
ObjectMeta: metav1.ObjectMeta{
60+
Name: "bad-secret",
61+
Namespace: namespace,
62+
Labels: map[string]string{
63+
constants.DevWorkspacePullSecretLabel: "true",
64+
},
65+
},
66+
Type: corev1.SecretTypeOpaque, // Not a docker config type
67+
},
68+
},
69+
setupInfra: func() {
70+
infrastructure.InitializeForTesting(infrastructure.Kubernetes)
71+
},
72+
expectedError: nil,
73+
expectedSecrets: []string{},
74+
},
75+
{
76+
name: "RetryError when OpenShift SA is too new with no secrets",
77+
objects: []client.Object{
78+
&corev1.ServiceAccount{
79+
TypeMeta: metav1.TypeMeta{
80+
Kind: "ServiceAccount",
81+
APIVersion: corev1.SchemeGroupVersion.String(),
82+
},
83+
ObjectMeta: metav1.ObjectMeta{
84+
Name: serviceAccountName,
85+
Namespace: namespace,
86+
CreationTimestamp: metav1.NewTime(time.Now()), // Recent
87+
},
88+
},
89+
},
90+
setupInfra: func() {
91+
infrastructure.InitializeForTesting(infrastructure.OpenShiftv4)
92+
},
93+
expectedError: &dwerrors.RetryError{},
94+
expectedSecrets: nil,
95+
},
96+
{
97+
name: "Non-OpenShift: no retry even if SA is recent with no secrets",
98+
objects: []client.Object{
99+
&corev1.ServiceAccount{
100+
TypeMeta: metav1.TypeMeta{
101+
Kind: "ServiceAccount",
102+
APIVersion: corev1.SchemeGroupVersion.String(),
103+
},
104+
ObjectMeta: metav1.ObjectMeta{
105+
Name: serviceAccountName,
106+
Namespace: namespace,
107+
CreationTimestamp: metav1.NewTime(time.Now()),
108+
},
109+
},
110+
},
111+
setupInfra: func() {
112+
infrastructure.InitializeForTesting(infrastructure.Kubernetes)
113+
},
114+
expectedError: nil,
115+
expectedSecrets: []string{},
116+
},
117+
{
118+
name: "Multiple SA + labeled secrets merged and sorted",
119+
objects: []client.Object{
120+
&corev1.ServiceAccount{
121+
TypeMeta: metav1.TypeMeta{
122+
Kind: "ServiceAccount",
123+
APIVersion: corev1.SchemeGroupVersion.String(),
124+
},
125+
ObjectMeta: metav1.ObjectMeta{
126+
Name: serviceAccountName,
127+
Namespace: namespace,
128+
CreationTimestamp: metav1.NewTime(time.Now().Add(-10 * time.Minute)),
129+
},
130+
ImagePullSecrets: []corev1.LocalObjectReference{
131+
{Name: "z-sa-secret"},
132+
},
133+
},
134+
&corev1.Secret{
135+
TypeMeta: metav1.TypeMeta{
136+
Kind: "Secret",
137+
APIVersion: corev1.SchemeGroupVersion.String(),
138+
},
139+
ObjectMeta: metav1.ObjectMeta{
140+
Name: "a-labeled-secret",
141+
Namespace: namespace,
142+
Labels: map[string]string{
143+
constants.DevWorkspacePullSecretLabel: "true",
144+
},
145+
},
146+
Type: corev1.SecretTypeDockerConfigJson,
147+
},
148+
},
149+
setupInfra: func() {
150+
infrastructure.InitializeForTesting(infrastructure.OpenShiftv4)
151+
},
152+
expectedError: nil,
153+
expectedSecrets: []string{"a-labeled-secret", "z-sa-secret"},
154+
},
155+
}
156+
157+
for _, tt := range tests {
158+
t.Run(tt.name, func(t *testing.T) {
159+
// Given
160+
scheme := runtime.NewScheme()
161+
assert.NoError(t, corev1.AddToScheme(scheme))
162+
tt.setupInfra()
163+
164+
fakeClient := fake.NewClientBuilder().
165+
WithScheme(scheme).
166+
WithObjects(tt.objects...).
167+
Build()
168+
169+
clusterAPI := sync.ClusterAPI{
170+
Client: fakeClient,
171+
}
172+
173+
// When
174+
result, err := PullSecrets(clusterAPI, serviceAccountName, namespace)
175+
176+
// Then
177+
if tt.expectedError != nil {
178+
assert.Error(t, err)
179+
assert.IsType(t, tt.expectedError, err)
180+
return
181+
}
182+
183+
assert.NoError(t, err)
184+
assert.NotNil(t, result)
185+
actualNames := []string{}
186+
for _, ps := range result.PullSecrets {
187+
actualNames = append(actualNames, ps.Name)
188+
}
189+
assert.Equal(t, tt.expectedSecrets, actualNames)
190+
})
191+
}
192+
}

0 commit comments

Comments
 (0)