@@ -1023,114 +1023,112 @@ var _ = Describe("The Openshift Notebook controller", func() {
1023
1023
)
1024
1024
1025
1025
var (
1026
- notebook * nbv1.Notebook
1027
- oauthClient * oauthv1.OAuthClient
1028
- oauthClientName string
1029
- ctx context.Context
1026
+ notebook * nbv1.Notebook
1027
+ ctx context.Context
1028
+ notebookKey types.NamespacedName
1030
1029
)
1031
1030
1032
- // Setup for all tests in this context
1033
- BeforeEach (func () {
1034
- ctx = context .Background ()
1035
- notebook = createNotebook (Name , Namespace )
1036
- oauthClientName = fmt .Sprintf ("%s-%s-%s" , Name , Namespace , "oauth-client" )
1037
-
1038
- oauthClient = & oauthv1.OAuthClient {
1039
- ObjectMeta : metav1.ObjectMeta {
1040
- Name : oauthClientName ,
1041
- },
1042
- RedirectURIs : []string {"https://www.kubeflow.org/" },
1043
- GrantMethod : oauthv1 .GrantHandlerAuto ,
1044
- }
1045
- })
1031
+ // Initialize context and keys once
1032
+ ctx = context .Background ()
1033
+ notebookKey = types.NamespacedName {Name : Name , Namespace : Namespace }
1046
1034
1047
- // Clean up resources after each test
1048
- AfterEach (func () {
1049
- nbToCleanup := & nbv1.Notebook {}
1050
- err := cli .Get (ctx , types.NamespacedName {Name : Name , Namespace : Namespace }, nbToCleanup )
1051
- if err == nil {
1052
- // Remove finalizers to allow deletion
1053
- nbToCleanup .Finalizers = nil
1054
- _ = cli .Update (ctx , nbToCleanup )
1055
- _ = cli .Delete (ctx , nbToCleanup )
1056
- }
1057
-
1058
- oauthClientToCleanup := & oauthv1.OAuthClient {}
1059
- err = cli .Get (ctx , types.NamespacedName {Name : oauthClientName }, oauthClientToCleanup )
1060
- if err == nil {
1061
- _ = cli .Delete (ctx , oauthClientToCleanup )
1062
- }
1063
- })
1035
+ // Create notebook once for all tests - WITH OAUTH ENABLED
1036
+ notebook = createNotebookWithOAuth (Name , Namespace )
1064
1037
1065
- It ("Should add a finalizer when a Notebook has been created " , func () {
1038
+ It ("Should create a Notebook CR successfully " , func () {
1066
1039
By ("Creating a new Notebook" )
1067
1040
Expect (cli .Create (ctx , notebook )).Should (Succeed ())
1068
1041
1069
- By ("Creating an OAuthClient" )
1070
- err := cli .Create (ctx , oauthClient )
1071
- if err != nil {
1072
- GinkgoT ().Logf ("OAuthClient creation result: %v" , err )
1073
- }
1074
-
1075
- By ("Adding the finalizer to the Notebook" )
1076
- key := types.NamespacedName {Name : Name , Namespace : Namespace }
1077
- Expect (cli .Get (ctx , key , notebook )).Should (Succeed ())
1078
-
1079
- notebook .Finalizers = append (notebook .Finalizers , Finalizer )
1080
- Expect (cli .Update (ctx , notebook )).Should (Succeed ())
1042
+ // Wait for the Reconciler to create the route, or else the OAuth reconciler
1043
+ // cannot create the OAuthClient object
1044
+ time .Sleep (3 * time .Second )
1045
+ })
1081
1046
1082
- By ("Verifying the finalizer is added to the Notebook" )
1083
- Expect (cli .Get (ctx , key , notebook )).Should (Succeed ())
1084
- Expect (notebook .Finalizers ).To (ContainElement (Finalizer ))
1047
+ It ("Should have finalizer set by controller or webhook" , func () {
1048
+ By ("Waiting for controller to add the finalizer" )
1049
+ Eventually (func () []string {
1050
+ var updated nbv1.Notebook
1051
+ err := cli .Get (ctx , notebookKey , & updated )
1052
+ if err != nil {
1053
+ return nil
1054
+ }
1055
+ return updated .Finalizers
1056
+ }, duration , interval ).Should (ContainElement (Finalizer ),
1057
+ "Expected finalizer '%s' to be added by controller" , Finalizer )
1085
1058
})
1086
1059
1087
- It ("Should delete the OAuthClient when the Notebook is deleted" , func () {
1088
- By ("Creating a Notebook with finalizer" )
1089
- notebook .Finalizers = []string {Finalizer }
1090
- Expect (cli .Create (ctx , notebook )).Should (Succeed ())
1060
+ It ("Should create OAuthClient for the Notebook CR" , func () {
1061
+ By ("Ensuring finalizer exists first" )
1062
+ Eventually (func () []string {
1063
+ var updated nbv1.Notebook
1064
+ cli .Get (ctx , notebookKey , & updated )
1065
+ return updated .Finalizers
1066
+ }, duration , interval ).Should (ContainElement (Finalizer ))
1067
+
1068
+ By ("Waiting for controller to create OAuthClient" )
1069
+ oauthClientKey := types.NamespacedName {Name : Name + "-" + Namespace + "-oauth-client" }
1070
+ createdOAuthClient := & oauthv1.OAuthClient {}
1071
+ Eventually (func () error {
1072
+ return cli .Get (ctx , oauthClientKey , createdOAuthClient )
1073
+ }, time .Second * 90 , time .Second * 3 ).Should (Succeed (),
1074
+ "Expected OAuthClient to be created by odh-notebook-controller" )
1075
+
1076
+ By ("Verifying OAuthClient has proper labels" )
1077
+ Expect (createdOAuthClient .Labels ).Should (
1078
+ HaveKeyWithValue ("notebook-owner" , Name ),
1079
+ "OAuthClient should have labels linking it to the notebook" )
1080
+ })
1091
1081
1092
- By ("Creating an OAuthClient" )
1093
- Expect (cli .Create (ctx , oauthClient )).Should (Succeed ())
1082
+ It ("Should delete OAuthClient when Notebook is deleted" , func () {
1083
+ By ("Ensuring prerequisite resources exist" )
1084
+ Eventually (func () []string {
1085
+ var updated nbv1.Notebook
1086
+ cli .Get (ctx , notebookKey , & updated )
1087
+ return updated .Finalizers
1088
+ }, duration , interval ).Should (ContainElement (Finalizer ))
1094
1089
1095
- By ("Requesting deletion of the Notebook" )
1096
- Expect (cli .Delete (ctx , notebook )).Should (Succeed ())
1090
+ oauthClientKey := types.NamespacedName {Name : Name + "-" + Namespace + "-oauth-client" }
1091
+ Eventually (func () error {
1092
+ return cli .Get (ctx , oauthClientKey , & oauthv1.OAuthClient {})
1093
+ }, duration , interval ).Should (Succeed ())
1097
1094
1098
- By ("Checking if the controller deletes the OAuthClient" )
1099
- oauthClientKey := types.NamespacedName {Name : oauthClientName }
1095
+ By ("Deleting the notebook" )
1096
+ var notebookToDelete nbv1.Notebook
1097
+ Expect (cli .Get (ctx , notebookKey , & notebookToDelete )).Should (Succeed ())
1098
+ Expect (cli .Delete (ctx , & notebookToDelete )).Should (Succeed ())
1100
1099
1101
- // First verify that the OAuthClient exists initially
1102
- Expect (cli .Get (ctx , oauthClientKey , oauthClient )).Should (Succeed ())
1100
+ By ("Verifying notebook is marked for deletion but persists due to finalizer" )
1101
+ Eventually (func () bool {
1102
+ var updated nbv1.Notebook
1103
+ err := cli .Get (ctx , notebookKey , & updated )
1104
+ return err == nil && updated .DeletionTimestamp != nil
1105
+ }, duration , interval ).Should (BeTrue (),
1106
+ "Notebook should be marked for deletion but persist due to finalizer" )
1103
1107
1104
- // Log the notebook state for debugging
1105
- key := types.NamespacedName {Name : notebook .Name , Namespace : notebook .Namespace }
1106
- nb := & nbv1.Notebook {}
1107
- if err := cli .Get (ctx , key , nb ); err == nil {
1108
- hasTimestamp := "no"
1109
- if nb .DeletionTimestamp != nil {
1110
- hasTimestamp = "yes"
1111
- }
1112
- GinkgoT ().Logf ("Notebook state: exists=true, has deletion timestamp=%s, finalizers=%v" ,
1113
- hasTimestamp , nb .Finalizers )
1114
- } else {
1115
- GinkgoT ().Logf ("Notebook state: exists=false, error=%v" , err )
1116
- }
1108
+ By ("Verifying controller deletes the OAuthClient" )
1109
+ Eventually (func () error {
1110
+ var oauth oauthv1.OAuthClient
1111
+ return cli .Get (ctx , oauthClientKey , & oauth )
1112
+ }, time .Second * 90 , time .Second * 3 ).Should (
1113
+ MatchError (ContainSubstring ("not found" )),
1114
+ "Expected OAuthClient to be deleted by odh-notebook-controller during finalizer processing" )
1115
+ })
1117
1116
1118
- // Wait for the controller to potentially delete the OAuthClient
1119
- // without any manual intervention
1120
- time .Sleep (5 * time .Second )
1121
-
1122
- // Check and log the final state
1123
- client := & oauthv1.OAuthClient {}
1124
- err := cli .Get (ctx , oauthClientKey , client )
1125
- if apierrors .IsNotFound (err ) {
1126
- GinkgoT ().Logf ("OAuthClient was successfully deleted by the controller" )
1127
- } else if err != nil {
1128
- GinkgoT ().Logf ("Error checking OAuthClient: %v" , err )
1129
- } else {
1130
- GinkgoT ().Logf ("OAuthClient still exists, which suggests the controller isn't handling deletion in the test environment" )
1131
- }
1117
+ It ("Should remove finalizer and delete Notebook after OAuthClient cleanup" , func () {
1118
+ By ("Verifying OAuthClient was deleted in previous test" )
1119
+ oauthClientKey := types.NamespacedName {Name : Name + "-" + Namespace + "-oauth-client" }
1120
+ Eventually (func () error {
1121
+ var oauth oauthv1.OAuthClient
1122
+ return cli .Get (ctx , oauthClientKey , & oauth )
1123
+ }, time .Second * 30 ).Should (MatchError (ContainSubstring ("not found" )))
1132
1124
1133
- // No assertion here - we're just observing behavior
1125
+ By ("Verifying finalizer is removed and notebook is deleted" )
1126
+ Eventually (func () error {
1127
+ var updated nbv1.Notebook
1128
+ return cli .Get (ctx , notebookKey , & updated )
1129
+ }, time .Second * 60 , time .Second * 2 ).Should (
1130
+ MatchError (ContainSubstring ("not found" )),
1131
+ "Expected Notebook to be fully deleted after finalizer removal" )
1134
1132
})
1135
1133
})
1136
1134
@@ -1466,6 +1464,75 @@ func createNotebook(name, namespace string) *nbv1.Notebook {
1466
1464
}
1467
1465
}
1468
1466
1467
+ func createNotebookWithOAuth (name , namespace string ) * nbv1.Notebook {
1468
+ return & nbv1.Notebook {
1469
+ ObjectMeta : metav1.ObjectMeta {
1470
+ Name : name ,
1471
+ Namespace : namespace ,
1472
+ Labels : map [string ]string {
1473
+ "app.kubernetes.io/instance" : name ,
1474
+ },
1475
+ Annotations : map [string ]string {
1476
+ "notebooks.opendatahub.io/inject-oauth" : "true" ,
1477
+ "notebooks.opendatahub.io/foo" : "bar" ,
1478
+ "notebooks.opendatahub.io/oauth-logout-url" : "https://example.notebook-url/notebook/" + namespace + "/" + name ,
1479
+ "kubeflow-resource-stopped" : "odh-notebook-controller-lock" ,
1480
+ },
1481
+ },
1482
+ Spec : nbv1.NotebookSpec {
1483
+ Template : nbv1.NotebookTemplateSpec {
1484
+ Spec : corev1.PodSpec {
1485
+ ServiceAccountName : name ,
1486
+ Containers : []corev1.Container {
1487
+ {
1488
+ Name : name ,
1489
+ Image : "registry.redhat.io/ubi8/ubi:latest" ,
1490
+ },
1491
+ createOAuthContainer (name , namespace ),
1492
+ },
1493
+ Volumes : []corev1.Volume {
1494
+ {
1495
+ Name : "notebook-data" ,
1496
+ VolumeSource : corev1.VolumeSource {
1497
+ PersistentVolumeClaim : & corev1.PersistentVolumeClaimVolumeSource {
1498
+ ClaimName : name + "-data" ,
1499
+ },
1500
+ },
1501
+ },
1502
+ {
1503
+ Name : "oauth-config" ,
1504
+ VolumeSource : corev1.VolumeSource {
1505
+ Secret : & corev1.SecretVolumeSource {
1506
+ SecretName : name + "-oauth-config" ,
1507
+ DefaultMode : ptr.To [int32 ](420 ),
1508
+ },
1509
+ },
1510
+ },
1511
+ {
1512
+ Name : "oauth-client" ,
1513
+ VolumeSource : corev1.VolumeSource {
1514
+ Secret : & corev1.SecretVolumeSource {
1515
+ SecretName : name + "-oauth-client" ,
1516
+ DefaultMode : ptr.To [int32 ](420 ),
1517
+ },
1518
+ },
1519
+ },
1520
+ {
1521
+ Name : "tls-certificates" ,
1522
+ VolumeSource : corev1.VolumeSource {
1523
+ Secret : & corev1.SecretVolumeSource {
1524
+ SecretName : name + "-tls" ,
1525
+ DefaultMode : ptr.To [int32 ](420 ),
1526
+ },
1527
+ },
1528
+ },
1529
+ },
1530
+ },
1531
+ },
1532
+ },
1533
+ }
1534
+ }
1535
+
1469
1536
func getRouteFromList (route * routev1.Route , notebook * nbv1.Notebook , name , namespace string ) (* routev1.Route , error ) {
1470
1537
routeList := & routev1.RouteList {}
1471
1538
opts := []client.ListOption {
0 commit comments