44 "context"
55 "errors"
66 "reflect"
7+ "strings"
78 "testing"
89 "time"
910 "unsafe"
@@ -55,6 +56,15 @@ func setStoreConfig(t *testing.T, cfgStore *store.BrowserConfigStore, key string
5556 m [key ] = spec
5657}
5758
59+ func envValue (env []corev1.EnvVar , key string ) (string , bool ) {
60+ for _ , item := range env {
61+ if item .Name == key {
62+ return item .Value , true
63+ }
64+ }
65+ return "" , false
66+ }
67+
5868func TestContainerStateEqual (t * testing.T ) {
5969 now := metav1 .NewTime (time .Now ().UTC ())
6070 a := corev1.ContainerState {Running : & corev1.ContainerStateRunning {StartedAt : now }}
@@ -149,7 +159,7 @@ func TestBuildBrowserPod(t *testing.T) {
149159 },
150160 }
151161
152- pod := buildBrowserPod (brw , cfg )
162+ pod := buildBrowserPod (brw , cfg , nil )
153163 if pod .Name != "b1" || pod .Namespace != "ns" {
154164 t .Fatalf ("unexpected pod identity" )
155165 }
@@ -167,6 +177,96 @@ func TestBuildBrowserPod(t *testing.T) {
167177 }
168178}
169179
180+ func TestParseSelenosisOptionsInvalidJSON (t * testing.T ) {
181+ ann := map [string ]string {
182+ selenosisOptionsAnnotationKey : "{nope" ,
183+ }
184+ _ , err := parseSelenosisOptions (ann )
185+ if err == nil {
186+ t .Fatalf ("expected error" )
187+ }
188+ if ! strings .Contains (err .Error (), selenosisOptionsAnnotationKey ) {
189+ t .Fatalf ("expected error to mention annotation key, got %v" , err )
190+ }
191+ }
192+
193+ func TestParseSelenosisOptionsEmpty (t * testing.T ) {
194+ opts , err := parseSelenosisOptions (nil )
195+ if err != nil {
196+ t .Fatalf ("expected no error, got %v" , err )
197+ }
198+ if opts != nil {
199+ t .Fatalf ("expected nil options for nil annotations" )
200+ }
201+
202+ opts , err = parseSelenosisOptions (map [string ]string {selenosisOptionsAnnotationKey : "" })
203+ if err != nil {
204+ t .Fatalf ("expected no error, got %v" , err )
205+ }
206+ if opts != nil {
207+ t .Fatalf ("expected nil options for empty annotation" )
208+ }
209+ }
210+
211+ func TestParseSelenosisOptionsValidJSON (t * testing.T ) {
212+ ann := map [string ]string {
213+ selenosisOptionsAnnotationKey : `{"labels":{"a":"b"},"containers":{"browser":{"env":{"X":"1"}}}}` ,
214+ }
215+ opts , err := parseSelenosisOptions (ann )
216+ if err != nil {
217+ t .Fatalf ("expected no error, got %v" , err )
218+ }
219+ if opts == nil || opts .Labels ["a" ] != "b" {
220+ t .Fatalf ("expected labels to be parsed" )
221+ }
222+ if opts .Containers ["browser" ].Env ["X" ] != "1" {
223+ t .Fatalf ("expected container env to be parsed" )
224+ }
225+ }
226+
227+ func TestApplySelenosisOptionsMergesEnvAndLabels (t * testing.T ) {
228+ pod := & corev1.Pod {
229+ ObjectMeta : metav1.ObjectMeta {
230+ Labels : map [string ]string {"existing" : "1" },
231+ },
232+ Spec : corev1.PodSpec {
233+ Containers : []corev1.Container {
234+ {
235+ Name : "browser" ,
236+ Env : []corev1.EnvVar {
237+ {Name : "A" , Value : "1" },
238+ {Name : "B" , Value : "2" },
239+ },
240+ },
241+ {Name : "sidecar" },
242+ },
243+ },
244+ }
245+ opts := & SelenosisOptions {
246+ Labels : map [string ]string {"from" : "options" },
247+ Containers : map [string ]ContainerOption {
248+ "browser" : {Env : map [string ]string {"B" : "override" , "C" : "new" }},
249+ },
250+ }
251+
252+ applySelenosisOptions (pod , opts )
253+
254+ if pod .Labels ["existing" ] != "1" || pod .Labels ["from" ] != "options" {
255+ t .Fatalf ("expected labels to be merged, got %+v" , pod .Labels )
256+ }
257+
258+ env := pod .Spec .Containers [0 ].Env
259+ if val , ok := envValue (env , "A" ); ! ok || val != "1" {
260+ t .Fatalf ("expected env A=1" )
261+ }
262+ if val , ok := envValue (env , "B" ); ! ok || val != "override" {
263+ t .Fatalf ("expected env B override" )
264+ }
265+ if val , ok := envValue (env , "C" ); ! ok || val != "new" {
266+ t .Fatalf ("expected env C new" )
267+ }
268+ }
269+
170270func TestHandleMissingPodConfigNotFound (t * testing.T ) {
171271 scheme := newBrowserScheme (t )
172272 cfgStore := store .NewBrowserConfigStore ()
@@ -264,6 +364,61 @@ func TestHandleMissingPodCreatesPod(t *testing.T) {
264364 }
265365}
266366
367+ func TestHandleMissingPodInvalidSelenosisOptions (t * testing.T ) {
368+ scheme := newBrowserScheme (t )
369+ cfgStore := store .NewBrowserConfigStore ()
370+ spec := & configv1.BrowserVersionConfigSpec {Image : "img" }
371+ setStoreConfig (t , cfgStore , "ns/chrome:120" , spec )
372+
373+ cl := newBrowserClient (scheme )
374+ r := NewBrowserReconciler (cl , cfgStore , scheme )
375+
376+ brw := & browserv1.Browser {
377+ ObjectMeta : metav1.ObjectMeta {
378+ Name : "b1" ,
379+ Namespace : "ns" ,
380+ Annotations : map [string ]string {
381+ selenosisOptionsAnnotationKey : "{bad-json" ,
382+ },
383+ },
384+ Spec : browserv1.BrowserSpec {
385+ BrowserName : "chrome" ,
386+ BrowserVersion : "120" ,
387+ },
388+ }
389+ if err := cl .Create (context .Background (), brw ); err != nil {
390+ t .Fatalf ("create browser: %v" , err )
391+ }
392+
393+ res , err := r .handleMissingPod (context .Background (), brw )
394+ if err != nil {
395+ t .Fatalf ("expected no error, got %v" , err )
396+ }
397+ if res .RequeueAfter != 0 {
398+ t .Fatalf ("expected no requeue, got %v" , res .RequeueAfter )
399+ }
400+
401+ updated := & browserv1.Browser {}
402+ if err := cl .Get (context .Background (), client.ObjectKey {Name : "b1" , Namespace : "ns" }, updated ); err != nil {
403+ t .Fatalf ("get browser: %v" , err )
404+ }
405+ if updated .Status .Phase != corev1 .PodFailed {
406+ t .Fatalf ("expected failed status, got %s" , updated .Status .Phase )
407+ }
408+ if updated .Status .Reason != "InvalidSelenosisOptions" {
409+ t .Fatalf ("expected reason InvalidSelenosisOptions, got %s" , updated .Status .Reason )
410+ }
411+
412+ pod := & corev1.Pod {}
413+ err = cl .Get (context .Background (), client.ObjectKey {Name : "b1" , Namespace : "ns" }, pod )
414+ if err == nil {
415+ t .Fatalf ("expected no pod to be created" )
416+ }
417+ if ! apierrors .IsNotFound (err ) {
418+ t .Fatalf ("expected not found error, got %v" , err )
419+ }
420+ }
421+
267422func TestUpdateBrowserStatusCriticalContainer (t * testing.T ) {
268423 scheme := newBrowserScheme (t )
269424 cl := newBrowserClient (scheme )
@@ -852,7 +1007,7 @@ func TestBuildBrowserPodWithInitContainersAndVolumes(t *testing.T) {
8521007 },
8531008 }
8541009
855- pod := buildBrowserPod (brw , cfg )
1010+ pod := buildBrowserPod (brw , cfg , nil )
8561011 if len (pod .Spec .InitContainers ) != 1 {
8571012 t .Fatalf ("expected init container" )
8581013 }
@@ -893,7 +1048,7 @@ func TestBuildBrowserPodInitContainerFields(t *testing.T) {
8931048 },
8941049 }
8951050
896- pod := buildBrowserPod (brw , cfg )
1051+ pod := buildBrowserPod (brw , cfg , nil )
8971052 if len (pod .Spec .InitContainers ) != 1 {
8981053 t .Fatalf ("expected init container" )
8991054 }
@@ -962,7 +1117,7 @@ func TestBuildBrowserPodAllFields(t *testing.T) {
9621117 },
9631118 }
9641119
965- pod := buildBrowserPod (brw , cfg )
1120+ pod := buildBrowserPod (brw , cfg , nil )
9661121 if pod .Spec .NodeSelector ["k" ] != "v" {
9671122 t .Fatalf ("expected node selector" )
9681123 }
@@ -995,7 +1150,7 @@ func TestBuildBrowserPodBrowserLabelsOnly(t *testing.T) {
9951150 },
9961151 }
9971152
998- pod := buildBrowserPod (brw , cfg )
1153+ pod := buildBrowserPod (brw , cfg , nil )
9991154 if pod .Labels ["only" ] != "browser" {
10001155 t .Fatalf ("expected browser labels to be applied" )
10011156 }
0 commit comments