Skip to content

Commit f7956e3

Browse files
committed
adding unit tests
1 parent 19e6aeb commit f7956e3

4 files changed

Lines changed: 228 additions & 4 deletions

File tree

internal/controller/appserver/deployment.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ func GenerateOLSDeployment(r reconciler.Reconciler, cr *olsv1alpha1.OLSConfig) (
389389
Annotations: map[string]string{
390390
utils.OLSConfigMapResourceVersionAnnotation: configMapResourceVersion,
391391
utils.OpenShiftMCPServerConfigMapResourceVersionAnnotation: mcpConfigMapResourceVersion,
392-
utils.ProxyCACertHashAnnotation: proxyCACMResourceVersion,
392+
utils.ProxyCACertHashAnnotation: proxyCACMResourceVersion,
393393
},
394394
},
395395
Spec: appsv1.DeploymentSpec{

internal/controller/lcore/deployment.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,7 @@ func generateLCoreServerDeployment(r reconciler.Reconciler, ctx context.Context,
997997
utils.LCoreConfigMapResourceVersionAnnotation: lcoreConfigMapResourceVersion,
998998
utils.LlamaStackConfigMapResourceVersionAnnotation: llamaStackConfigMapResourceVersion,
999999
utils.OpenShiftMCPServerConfigMapResourceVersionAnnotation: mcpConfigMapResourceVersion,
1000-
utils.ProxyCACertHashAnnotation: proxyCACMResourceVersion,
1000+
utils.ProxyCACertHashAnnotation: proxyCACMResourceVersion,
10011001
},
10021002
},
10031003
Spec: appsv1.DeploymentSpec{
@@ -1276,7 +1276,7 @@ func generateLCoreLibraryDeployment(r reconciler.Reconciler, ctx context.Context
12761276
utils.LCoreConfigMapResourceVersionAnnotation: lcoreConfigMapResourceVersion,
12771277
utils.LlamaStackConfigMapResourceVersionAnnotation: llamaStackConfigMapResourceVersion,
12781278
utils.OpenShiftMCPServerConfigMapResourceVersionAnnotation: mcpConfigMapResourceVersion,
1279-
utils.ProxyCACertHashAnnotation: proxyCACMResourceVersion,
1279+
utils.ProxyCACertHashAnnotation: proxyCACMResourceVersion,
12801280
},
12811281
},
12821282
Spec: appsv1.DeploymentSpec{

internal/controller/utils/constants.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ const (
108108
// AdditionalCAHashKey is the key of the hash value of the additional CA certificates in the deployment annotations
109109
AdditionalCAHashKey = "hash/additionalca"
110110
// ProxyCACertHashAnnotation is the annotation key for tracking Proxy CA certificate content hash.
111-
ProxyCACertHashAnnotation = "ols.openshift.io/proxy-ca-configmap-version"
111+
ProxyCACertHashAnnotation = "ols.openshift.io/proxy-ca-configmap-hash"
112112
// OLSAppServerContainerPort is the port number of the lightspeed-service-api container exposes
113113
OLSAppServerContainerPort = 8443
114114
// OLSAppServerServicePort is the port number for OLS application server service.
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
package utils
2+
3+
import (
4+
"context"
5+
"crypto/sha256"
6+
"encoding/hex"
7+
8+
. "github.com/onsi/ginkgo/v2"
9+
. "github.com/onsi/gomega"
10+
corev1 "k8s.io/api/core/v1"
11+
apierrors "k8s.io/apimachinery/pkg/api/errors"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"k8s.io/client-go/kubernetes/scheme"
14+
"sigs.k8s.io/controller-runtime/pkg/client"
15+
logf "sigs.k8s.io/controller-runtime/pkg/log"
16+
17+
olsv1alpha1 "github.com/openshift/lightspeed-operator/api/v1alpha1"
18+
)
19+
20+
var _ = Describe("GetProxyCACertHash", func() {
21+
var (
22+
ctx context.Context
23+
testReconciler *TestReconciler
24+
testOLSConfig *olsv1alpha1.OLSConfig
25+
testConfigMap *corev1.ConfigMap
26+
testCertContent string
27+
testConfigMapName string
28+
testCertKey string
29+
)
30+
31+
BeforeEach(func() {
32+
ctx = context.Background()
33+
testCertContent = "-----BEGIN CERTIFICATE-----\nMIIDXTCCAkWgAwIBAgIJAKZ7VZ\n-----END CERTIFICATE-----"
34+
testConfigMapName = "test-proxy-ca-cm"
35+
testCertKey = ProxyCACertFileName
36+
37+
testReconciler = NewTestReconciler(k8sClient, logf.Log, scheme.Scheme, OLSNamespaceDefault)
38+
39+
testOLSConfig = &olsv1alpha1.OLSConfig{
40+
ObjectMeta: metav1.ObjectMeta{
41+
Name: "test-olsconfig",
42+
},
43+
Spec: olsv1alpha1.OLSConfigSpec{
44+
OLSConfig: olsv1alpha1.OLSSpec{
45+
ProxyConfig: &olsv1alpha1.ProxyConfig{
46+
ProxyURL: "https://proxy.example.com:8443",
47+
ProxyCACertificateRef: &olsv1alpha1.ProxyCACertConfigMapRef{
48+
LocalObjectReference: corev1.LocalObjectReference{
49+
Name: testConfigMapName,
50+
},
51+
Key: testCertKey,
52+
},
53+
},
54+
},
55+
},
56+
}
57+
58+
testConfigMap = &corev1.ConfigMap{
59+
ObjectMeta: metav1.ObjectMeta{
60+
Name: testConfigMapName,
61+
Namespace: OLSNamespaceDefault,
62+
},
63+
Data: map[string]string{
64+
testCertKey: testCertContent,
65+
},
66+
}
67+
})
68+
69+
AfterEach(func() {
70+
if testConfigMap != nil {
71+
_ = k8sClient.Delete(ctx, testConfigMap)
72+
}
73+
})
74+
75+
Context("when proxy CA is configured", func() {
76+
It("should return the SHA256 hash of the certificate content", func() {
77+
Expect(k8sClient.Create(ctx, testConfigMap)).To(Succeed())
78+
79+
hash, err := GetProxyCACertHash(testReconciler, ctx, testOLSConfig)
80+
81+
Expect(err).NotTo(HaveOccurred())
82+
83+
expectedHash := sha256.Sum256([]byte(testCertContent))
84+
expectedHashString := hex.EncodeToString(expectedHash[:])
85+
86+
Expect(hash).To(Equal(expectedHashString))
87+
})
88+
89+
It("should return consistent hash for same certificate content", func() {
90+
Expect(k8sClient.Create(ctx, testConfigMap)).To(Succeed())
91+
92+
hash1, err1 := GetProxyCACertHash(testReconciler, ctx, testOLSConfig)
93+
hash2, err2 := GetProxyCACertHash(testReconciler, ctx, testOLSConfig)
94+
95+
Expect(err1).NotTo(HaveOccurred())
96+
Expect(err2).NotTo(HaveOccurred())
97+
Expect(hash1).To(Equal(hash2))
98+
Expect(hash1).NotTo(BeEmpty())
99+
})
100+
101+
It("should return different hash when certificate content changes", func() {
102+
Expect(k8sClient.Create(ctx, testConfigMap)).To(Succeed())
103+
104+
hash1, err := GetProxyCACertHash(testReconciler, ctx, testOLSConfig)
105+
Expect(err).NotTo(HaveOccurred())
106+
107+
testConfigMap.Data[testCertKey] = "-----BEGIN CERTIFICATE-----\nDIFFERENT_CERT\n-----END CERTIFICATE-----"
108+
Expect(k8sClient.Update(ctx, testConfigMap)).To(Succeed())
109+
110+
hash2, err := GetProxyCACertHash(testReconciler, ctx, testOLSConfig)
111+
Expect(err).NotTo(HaveOccurred())
112+
113+
Expect(hash1).NotTo(Equal(hash2))
114+
Expect(hash1).NotTo(BeEmpty())
115+
Expect(hash2).NotTo(BeEmpty())
116+
})
117+
118+
It("should return error when ConfigMap does not exist", func() {
119+
hash, err := GetProxyCACertHash(testReconciler, ctx, testOLSConfig)
120+
121+
Expect(err).To(HaveOccurred())
122+
Expect(apierrors.IsNotFound(err)).To(BeTrue())
123+
Expect(hash).To(BeEmpty())
124+
})
125+
126+
It("should return error when certificate key is missing from ConfigMap", func() {
127+
testConfigMap.Data = map[string]string{
128+
"wrong-key": testCertContent,
129+
}
130+
Expect(k8sClient.Create(ctx, testConfigMap)).To(Succeed())
131+
132+
hash, err := GetProxyCACertHash(testReconciler, ctx, testOLSConfig)
133+
134+
Expect(err).To(HaveOccurred())
135+
Expect(err.Error()).To(ContainSubstring("not found in ConfigMap"))
136+
Expect(hash).To(BeEmpty())
137+
})
138+
139+
It("should use custom key when specified in ProxyCACertificateRef", func() {
140+
customKey := "custom-ca.crt"
141+
testOLSConfig.Spec.OLSConfig.ProxyConfig.ProxyCACertificateRef.Key = customKey
142+
testConfigMap.Data = map[string]string{
143+
customKey: testCertContent,
144+
}
145+
Expect(k8sClient.Create(ctx, testConfigMap)).To(Succeed())
146+
147+
hash, err := GetProxyCACertHash(testReconciler, ctx, testOLSConfig)
148+
149+
Expect(err).NotTo(HaveOccurred())
150+
Expect(hash).NotTo(BeEmpty())
151+
152+
expectedHash := sha256.Sum256([]byte(testCertContent))
153+
expectedHashString := hex.EncodeToString(expectedHash[:])
154+
Expect(hash).To(Equal(expectedHashString))
155+
})
156+
})
157+
158+
Context("when proxy is not configured", func() {
159+
It("should return empty string when ProxyConfig is nil", func() {
160+
testOLSConfig.Spec.OLSConfig.ProxyConfig = nil
161+
162+
hash, err := GetProxyCACertHash(testReconciler, ctx, testOLSConfig)
163+
164+
Expect(err).NotTo(HaveOccurred())
165+
Expect(hash).To(BeEmpty())
166+
})
167+
168+
It("should return empty string when ProxyCACertificateRef is nil", func() {
169+
testOLSConfig.Spec.OLSConfig.ProxyConfig.ProxyCACertificateRef = nil
170+
171+
hash, err := GetProxyCACertHash(testReconciler, ctx, testOLSConfig)
172+
173+
Expect(err).NotTo(HaveOccurred())
174+
Expect(hash).To(BeEmpty())
175+
})
176+
177+
It("should return empty string when ConfigMap name is empty", func() {
178+
testOLSConfig.Spec.OLSConfig.ProxyConfig.ProxyCACertificateRef.Name = ""
179+
180+
hash, err := GetProxyCACertHash(testReconciler, ctx, testOLSConfig)
181+
182+
Expect(err).NotTo(HaveOccurred())
183+
Expect(hash).To(BeEmpty())
184+
})
185+
})
186+
187+
Context("hash validation for reconciliation behavior", func() {
188+
It("should detect actual certificate changes (not just ResourceVersion changes)", func() {
189+
// This validates the main purpose: deployments only restart when certificate
190+
// content changes, not when ConfigMap ResourceVersion changes (e.g., service-ca updates)
191+
192+
Expect(k8sClient.Create(ctx, testConfigMap)).To(Succeed())
193+
194+
hash1, err := GetProxyCACertHash(testReconciler, ctx, testOLSConfig)
195+
Expect(err).NotTo(HaveOccurred())
196+
Expect(hash1).NotTo(BeEmpty())
197+
198+
cm := &corev1.ConfigMap{}
199+
Expect(k8sClient.Get(ctx, client.ObjectKey{Name: testConfigMapName, Namespace: OLSNamespaceDefault}, cm)).To(Succeed())
200+
201+
if cm.Annotations == nil {
202+
cm.Annotations = make(map[string]string)
203+
}
204+
cm.Annotations["test-annotation"] = "test-value"
205+
Expect(k8sClient.Update(ctx, cm)).To(Succeed())
206+
207+
hash2, err := GetProxyCACertHash(testReconciler, ctx, testOLSConfig)
208+
Expect(err).NotTo(HaveOccurred())
209+
210+
// Hash should be identical because certificate content didn't change
211+
Expect(hash2).To(Equal(hash1))
212+
213+
cm.Data[testCertKey] = "-----BEGIN CERTIFICATE-----\nNEW_CERT\n-----END CERTIFICATE-----"
214+
Expect(k8sClient.Update(ctx, cm)).To(Succeed())
215+
216+
hash3, err := GetProxyCACertHash(testReconciler, ctx, testOLSConfig)
217+
Expect(err).NotTo(HaveOccurred())
218+
219+
// Hash should be different because certificate content changed
220+
Expect(hash3).NotTo(Equal(hash1))
221+
Expect(hash3).NotTo(Equal(hash2))
222+
})
223+
})
224+
})

0 commit comments

Comments
 (0)