@@ -19,6 +19,7 @@ import (
19
19
"context"
20
20
"crypto/x509"
21
21
"encoding/pem"
22
+ "errors"
22
23
"fmt"
23
24
"os"
24
25
"time"
@@ -313,6 +314,131 @@ var _ = Describe("The Openshift Notebook controller", func() {
313
314
314
315
})
315
316
317
+ // New test case for notebook creation with long name
318
+ When ("Creating a long named Notebook" , func () {
319
+
320
+ // With the work done https://issues.redhat.com/browse/RHOAIENG-4148,
321
+ // 48 characters is the maximum length for a notebook name.
322
+ // This would the extent of the test.
323
+ // TODO: Update the test to use the maximum length when the work is done.
324
+ const (
325
+ Name = "test-notebook-with-a-very-long-name-thats-48char"
326
+ Namespace = "default"
327
+ )
328
+
329
+ notebook := createNotebook (Name , Namespace )
330
+
331
+ expectedRoute := routev1.Route {
332
+ ObjectMeta : metav1.ObjectMeta {
333
+ GenerateName : "nb-" ,
334
+ Namespace : Namespace ,
335
+ Labels : map [string ]string {
336
+ "notebook-name" : Name ,
337
+ },
338
+ },
339
+ Spec : routev1.RouteSpec {
340
+ To : routev1.RouteTargetReference {
341
+ Kind : "Service" ,
342
+ Name : Name ,
343
+ Weight : ptr.To [int32 ](100 ),
344
+ },
345
+ Port : & routev1.RoutePort {
346
+ TargetPort : intstr .FromString ("http-" + Name ),
347
+ },
348
+ TLS : & routev1.TLSConfig {
349
+ Termination : routev1 .TLSTerminationEdge ,
350
+ InsecureEdgeTerminationPolicy : routev1 .InsecureEdgeTerminationPolicyRedirect ,
351
+ },
352
+ WildcardPolicy : routev1 .WildcardPolicyNone ,
353
+ },
354
+ Status : routev1.RouteStatus {
355
+ Ingress : []routev1.RouteIngress {},
356
+ },
357
+ }
358
+
359
+ route := & routev1.Route {}
360
+
361
+ It ("Should create a Route to expose the traffic externally" , func () {
362
+ ctx := context .Background ()
363
+
364
+ By ("By creating a new Notebook" )
365
+ Expect (cli .Create (ctx , notebook )).Should (Succeed ())
366
+ time .Sleep (interval )
367
+
368
+ By ("By checking that the controller has created the Route" )
369
+ Eventually (func () error {
370
+ route , err := getRouteFromList (route , notebook , Name , Namespace )
371
+ if route == nil {
372
+ return err
373
+ }
374
+ return nil
375
+ }, duration , interval ).Should (Succeed ())
376
+ Expect (* route ).To (BeMatchingK8sResource (expectedRoute , CompareNotebookRoutes ))
377
+ })
378
+
379
+ It ("Should reconcile the Route when modified" , func () {
380
+ By ("By simulating a manual Route modification" )
381
+ patch := client .RawPatch (types .MergePatchType , []byte (`{"spec":{"to":{"name":"foo"}}}` ))
382
+ Expect (cli .Patch (ctx , route , patch )).Should (Succeed ())
383
+ time .Sleep (interval )
384
+
385
+ By ("By checking that the controller has restored the Route spec" )
386
+ Eventually (func () (string , error ) {
387
+ route , err := getRouteFromList (route , notebook , Name , Namespace )
388
+ if route == nil {
389
+ return "" , err
390
+ }
391
+ return route .Spec .To .Name , nil
392
+ }, duration , interval ).Should (Equal (Name ))
393
+ Expect (* route ).To (BeMatchingK8sResource (expectedRoute , CompareNotebookRoutes ))
394
+ })
395
+
396
+ It ("Should recreate the Route when deleted" , func () {
397
+ By ("By deleting the notebook route" )
398
+ Expect (cli .Delete (ctx , route )).Should (Succeed ())
399
+ time .Sleep (interval )
400
+
401
+ By ("By checking that the controller has recreated the Route" )
402
+ Eventually (func () error {
403
+ route , err := getRouteFromList (route , notebook , Name , Namespace )
404
+ if route == nil {
405
+ return err
406
+ }
407
+ return nil
408
+ }, duration , interval ).Should (Succeed ())
409
+ Expect (* route ).To (BeMatchingK8sResource (expectedRoute , CompareNotebookRoutes ))
410
+ })
411
+
412
+ It ("Should delete the Openshift Route" , func () {
413
+ // Testenv cluster does not implement Kubernetes GC:
414
+ // https://book.kubebuilder.io/reference/envtest.html#testing-considerations
415
+ // To test that the deletion lifecycle works, test the ownership
416
+ // instead of asserting on existence.
417
+ expectedOwnerReference := metav1.OwnerReference {
418
+ APIVersion : "kubeflow.org/v1" ,
419
+ Kind : "Notebook" ,
420
+ Name : Name ,
421
+ UID : notebook .GetObjectMeta ().GetUID (),
422
+ Controller : ptr .To (true ),
423
+ BlockOwnerDeletion : ptr .To (true ),
424
+ }
425
+
426
+ By ("By checking that the Notebook owns the Route object" )
427
+ Expect (route .GetObjectMeta ().GetOwnerReferences ()).To (ContainElement (expectedOwnerReference ))
428
+
429
+ By ("By deleting the recently created Notebook" )
430
+ Expect (cli .Delete (ctx , notebook )).Should (Succeed ())
431
+ time .Sleep (interval )
432
+
433
+ By ("By checking that the Notebook is deleted" )
434
+ Eventually (func () error {
435
+ key := types.NamespacedName {Name : Name , Namespace : Namespace }
436
+ return cli .Get (ctx , key , notebook )
437
+ }, duration , interval ).Should (HaveOccurred ())
438
+ })
439
+
440
+ })
441
+
316
442
// New test case for notebook update
317
443
When ("Updating a Notebook" , func () {
318
444
const (
@@ -939,7 +1065,12 @@ var _ = Describe("The Openshift Notebook controller", func() {
939
1065
})
940
1066
941
1067
It ("Should not create OAuth secret" , func () {
942
- secrets := & corev1.SecretList {}
1068
+ secrets := & corev1.SecretList {
1069
+ TypeMeta : metav1.TypeMeta {
1070
+ Kind : "SecretList" ,
1071
+ APIVersion : "v1" ,
1072
+ },
1073
+ }
943
1074
Eventually (func () error {
944
1075
return cli .List (context .Background (), secrets , client .InNamespace (namespace ))
945
1076
}, duration , interval ).Should (Succeed ())
@@ -967,6 +1098,28 @@ func createNotebook(name, namespace string) *nbv1.Notebook {
967
1098
}
968
1099
}
969
1100
1101
+ func getRouteFromList (route * routev1.Route , notebook * nbv1.Notebook , name , namespace string ) (* routev1.Route , error ) {
1102
+ routeList := & routev1.RouteList {}
1103
+ opts := []client.ListOption {
1104
+ client .InNamespace (namespace ),
1105
+ client.MatchingLabels {"notebook-name" : name },
1106
+ }
1107
+
1108
+ err := cli .List (ctx , routeList , opts ... )
1109
+ if err != nil {
1110
+ return nil , err
1111
+ }
1112
+
1113
+ // Get the route from the list
1114
+ for _ , nRoute := range routeList .Items {
1115
+ if metav1 .IsControlledBy (& nRoute , notebook ) {
1116
+ * route = nRoute
1117
+ return route , nil
1118
+ }
1119
+ }
1120
+ return nil , errors .New ("Route not found" )
1121
+ }
1122
+
970
1123
func createOAuthServiceAccount (name , namespace string ) corev1.ServiceAccount {
971
1124
return corev1.ServiceAccount {
972
1125
ObjectMeta : metav1.ObjectMeta {
0 commit comments