Skip to content

Commit 133c222

Browse files
committed
chore(falconcontainer): Add injector tests
1 parent deccff1 commit 133c222

File tree

2 files changed

+285
-1
lines changed

2 files changed

+285
-1
lines changed

internal/controller/falcon_container/injector.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (r *FalconContainerReconciler) reconcileInjectorTLSSecret(ctx context.Conte
5858
}
5959
return injectorTLSSecret, r.Create(ctx, log, falconContainer, injectorTLSSecret)
6060
}
61-
return &corev1.Secret{}, fmt.Errorf("unable to query existing injector TL secret %s: %v", injectorTLSSecretName, err)
61+
return &corev1.Secret{}, fmt.Errorf("unable to query existing injector TLS secret %s: %v", injectorTLSSecretName, err)
6262
}
6363
return existingInjectorTLSSecret, nil
6464

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
package falcon
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
falconv1alpha1 "github.com/crowdstrike/falcon-operator/api/falcon/v1alpha1"
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
corev1 "k8s.io/api/core/v1"
11+
"k8s.io/apimachinery/pkg/api/errors"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"k8s.io/apimachinery/pkg/runtime"
14+
"sigs.k8s.io/controller-runtime/pkg/client"
15+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
16+
"sigs.k8s.io/controller-runtime/pkg/log/zap"
17+
)
18+
19+
// Mock client that returns errors for testing error handling
20+
type erroringClient struct {
21+
client.Client
22+
}
23+
24+
func (e *erroringClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
25+
return errors.NewBadRequest("test error")
26+
}
27+
28+
func TestReconcileInjectorTLSSecretLogic(t *testing.T) {
29+
ctx := context.Background()
30+
log := zap.New(zap.UseDevMode(true))
31+
32+
// Create test scheme
33+
scheme := runtime.NewScheme()
34+
require.NoError(t, corev1.AddToScheme(scheme))
35+
require.NoError(t, falconv1alpha1.AddToScheme(scheme))
36+
37+
t.Run("should return existing secret when found", func(t *testing.T) {
38+
existingSecret := &corev1.Secret{
39+
ObjectMeta: metav1.ObjectMeta{
40+
Name: injectorTLSSecretName,
41+
Namespace: "test-namespace",
42+
},
43+
Type: corev1.SecretTypeTLS,
44+
Data: map[string][]byte{
45+
"tls.crt": []byte("existing-cert"),
46+
"tls.key": []byte("existing-key"),
47+
"ca.crt": []byte("existing-ca"),
48+
},
49+
}
50+
51+
falconContainer := &falconv1alpha1.FalconContainer{
52+
ObjectMeta: metav1.ObjectMeta{
53+
Name: "test-falcon-container",
54+
Namespace: "test-namespace",
55+
},
56+
Spec: falconv1alpha1.FalconContainerSpec{
57+
InstallNamespace: "test-namespace",
58+
Injector: falconv1alpha1.FalconContainerInjectorSpec{
59+
TLS: falconv1alpha1.FalconContainerInjectorTLS{},
60+
},
61+
},
62+
}
63+
64+
fakeClient := fake.NewClientBuilder().
65+
WithScheme(scheme).
66+
WithObjects(existingSecret, falconContainer).
67+
Build()
68+
69+
reconciler := &FalconContainerReconciler{
70+
Client: fakeClient,
71+
Reader: fakeClient,
72+
Scheme: scheme,
73+
}
74+
75+
secret, err := reconciler.reconcileInjectorTLSSecret(ctx, log, falconContainer)
76+
77+
require.NoError(t, err)
78+
assert.NotNil(t, secret)
79+
assert.Equal(t, injectorTLSSecretName, secret.Name)
80+
assert.Equal(t, "test-namespace", secret.Namespace)
81+
assert.Equal(t, []byte("existing-cert"), secret.Data["tls.crt"])
82+
assert.Equal(t, []byte("existing-key"), secret.Data["tls.key"])
83+
assert.Equal(t, []byte("existing-ca"), secret.Data["ca.crt"])
84+
})
85+
86+
t.Run("should handle default validity configuration", func(t *testing.T) {
87+
falconContainer := &falconv1alpha1.FalconContainer{
88+
ObjectMeta: metav1.ObjectMeta{
89+
Name: "test-falcon-container",
90+
Namespace: "test-namespace",
91+
},
92+
Spec: falconv1alpha1.FalconContainerSpec{
93+
InstallNamespace: "test-namespace",
94+
Injector: falconv1alpha1.FalconContainerInjectorSpec{
95+
TLS: falconv1alpha1.FalconContainerInjectorTLS{
96+
Validity: nil, // Should use default 3650
97+
},
98+
},
99+
},
100+
}
101+
102+
validity := 3650
103+
if falconContainer.Spec.Injector.TLS.Validity != nil {
104+
validity = *falconContainer.Spec.Injector.TLS.Validity
105+
}
106+
107+
assert.Equal(t, 3650, validity)
108+
})
109+
110+
t.Run("should handle custom validity configuration", func(t *testing.T) {
111+
customValidity := 1000
112+
falconContainer := &falconv1alpha1.FalconContainer{
113+
ObjectMeta: metav1.ObjectMeta{
114+
Name: "test-falcon-container",
115+
Namespace: "test-namespace",
116+
},
117+
Spec: falconv1alpha1.FalconContainerSpec{
118+
InstallNamespace: "test-namespace",
119+
Injector: falconv1alpha1.FalconContainerInjectorSpec{
120+
TLS: falconv1alpha1.FalconContainerInjectorTLS{
121+
Validity: &customValidity,
122+
},
123+
},
124+
},
125+
}
126+
127+
validity := 3650
128+
if falconContainer.Spec.Injector.TLS.Validity != nil {
129+
validity = *falconContainer.Spec.Injector.TLS.Validity
130+
}
131+
132+
assert.Equal(t, 1000, validity)
133+
})
134+
135+
t.Run("should handle errors from GetNamespacedObject", func(t *testing.T) {
136+
falconContainer := &falconv1alpha1.FalconContainer{
137+
ObjectMeta: metav1.ObjectMeta{
138+
Name: "test-falcon-container",
139+
Namespace: "test-namespace",
140+
},
141+
Spec: falconv1alpha1.FalconContainerSpec{
142+
InstallNamespace: "test-namespace",
143+
Injector: falconv1alpha1.FalconContainerInjectorSpec{
144+
TLS: falconv1alpha1.FalconContainerInjectorTLS{},
145+
},
146+
},
147+
}
148+
149+
// Create a fake client that will return an error
150+
fakeClient := fake.NewClientBuilder().WithScheme(scheme).Build()
151+
152+
reconciler := &FalconContainerReconciler{
153+
Client: &erroringClient{Client: fakeClient},
154+
Reader: &erroringClient{Client: fakeClient},
155+
Scheme: scheme,
156+
}
157+
158+
secret, err := reconciler.reconcileInjectorTLSSecret(ctx, log, falconContainer)
159+
160+
assert.Error(t, err)
161+
assert.Contains(t, err.Error(), "unable to query existing injector TLS secret")
162+
assert.NotNil(t, secret) // Should return empty secret on error
163+
})
164+
165+
t.Run("should handle validity boundary values", func(t *testing.T) {
166+
testCases := []struct {
167+
name string
168+
validity *int
169+
expectedValidity int
170+
}{
171+
{
172+
name: "nil validity uses default",
173+
validity: nil,
174+
expectedValidity: 3650,
175+
},
176+
{
177+
name: "minimum validity (0)",
178+
validity: &[]int{0}[0],
179+
expectedValidity: 0,
180+
},
181+
{
182+
name: "single digit validity",
183+
validity: &[]int{1}[0],
184+
expectedValidity: 1,
185+
},
186+
{
187+
name: "maximum validity (9999)",
188+
validity: &[]int{9999}[0],
189+
expectedValidity: 9999,
190+
},
191+
}
192+
193+
for _, tc := range testCases {
194+
t.Run(tc.name, func(t *testing.T) {
195+
falconContainer := &falconv1alpha1.FalconContainer{
196+
Spec: falconv1alpha1.FalconContainerSpec{
197+
Injector: falconv1alpha1.FalconContainerInjectorSpec{
198+
TLS: falconv1alpha1.FalconContainerInjectorTLS{
199+
Validity: tc.validity,
200+
},
201+
},
202+
},
203+
}
204+
205+
validity := 3650
206+
if falconContainer.Spec.Injector.TLS.Validity != nil {
207+
validity = *falconContainer.Spec.Injector.TLS.Validity
208+
}
209+
210+
assert.Equal(t, tc.expectedValidity, validity)
211+
})
212+
}
213+
})
214+
}
215+
216+
func TestReconcileInjectorTLSSecretIntegrationScenarios(t *testing.T) {
217+
ctx := context.Background()
218+
log := zap.New(zap.UseDevMode(true))
219+
220+
// Create test scheme
221+
scheme := runtime.NewScheme()
222+
require.NoError(t, corev1.AddToScheme(scheme))
223+
require.NoError(t, falconv1alpha1.AddToScheme(scheme))
224+
225+
t.Run("secret data should have correct TLS structure", func(t *testing.T) {
226+
existingSecret := &corev1.Secret{
227+
ObjectMeta: metav1.ObjectMeta{
228+
Name: injectorTLSSecretName,
229+
Namespace: "test-namespace",
230+
},
231+
Type: corev1.SecretTypeTLS,
232+
Data: map[string][]byte{
233+
"tls.crt": []byte("-----BEGIN CERTIFICATE-----\nfake-cert\n-----END CERTIFICATE-----"),
234+
"tls.key": []byte("-----BEGIN PRIVATE KEY-----\nfake-key\n-----END PRIVATE KEY-----"),
235+
"ca.crt": []byte("-----BEGIN CERTIFICATE-----\nfake-ca\n-----END CERTIFICATE-----"),
236+
},
237+
}
238+
239+
falconContainer := &falconv1alpha1.FalconContainer{
240+
ObjectMeta: metav1.ObjectMeta{
241+
Name: "test-falcon-container",
242+
Namespace: "test-namespace",
243+
},
244+
Spec: falconv1alpha1.FalconContainerSpec{
245+
InstallNamespace: "test-namespace",
246+
Injector: falconv1alpha1.FalconContainerInjectorSpec{
247+
TLS: falconv1alpha1.FalconContainerInjectorTLS{},
248+
},
249+
},
250+
}
251+
252+
fakeClient := fake.NewClientBuilder().
253+
WithScheme(scheme).
254+
WithObjects(existingSecret, falconContainer).
255+
Build()
256+
257+
reconciler := &FalconContainerReconciler{
258+
Client: fakeClient,
259+
Reader: fakeClient,
260+
Scheme: scheme,
261+
}
262+
263+
secret, err := reconciler.reconcileInjectorTLSSecret(ctx, log, falconContainer)
264+
265+
require.NoError(t, err)
266+
assert.Equal(t, corev1.SecretTypeTLS, secret.Type)
267+
268+
// Verify all required TLS keys are present
269+
requiredKeys := []string{"tls.crt", "tls.key", "ca.crt"}
270+
for _, key := range requiredKeys {
271+
assert.Contains(t, secret.Data, key, "Secret should contain %s", key)
272+
assert.NotEmpty(t, secret.Data[key], "Secret key %s should not be empty", key)
273+
}
274+
275+
// Verify certificate-like structure (basic validation)
276+
tlsCert := string(secret.Data["tls.crt"])
277+
tlsKey := string(secret.Data["tls.key"])
278+
caCert := string(secret.Data["ca.crt"])
279+
280+
assert.Contains(t, tlsCert, "CERTIFICATE", "tls.crt should contain certificate markers")
281+
assert.Contains(t, tlsKey, "PRIVATE KEY", "tls.key should contain private key markers")
282+
assert.Contains(t, caCert, "CERTIFICATE", "ca.crt should contain certificate markers")
283+
})
284+
}

0 commit comments

Comments
 (0)