19
19
list_all_queued ,
20
20
)
21
21
from codeflare_sdk .common .utils .unit_test_support import (
22
- createClusterWithConfig ,
22
+ create_cluster ,
23
23
arg_check_del_effect ,
24
24
ingress_retrieval ,
25
25
arg_check_apply_effect ,
26
26
get_local_queue ,
27
- createClusterConfig ,
27
+ create_cluster_config ,
28
28
get_ray_obj ,
29
29
get_obj_none ,
30
30
get_ray_obj_with_status ,
31
31
get_aw_obj_with_status ,
32
+ patch_cluster_with_dynamic_client ,
33
+ route_list_retrieval ,
32
34
)
33
35
from codeflare_sdk .ray .cluster .cluster import _is_openshift_cluster
34
36
from pathlib import Path
@@ -67,11 +69,189 @@ def test_cluster_up_down(mocker):
67
69
"kubernetes.client.CustomObjectsApi.list_namespaced_custom_object" ,
68
70
return_value = get_local_queue ("kueue.x-k8s.io" , "v1beta1" , "ns" , "localqueues" ),
69
71
)
70
- cluster = cluster = createClusterWithConfig (mocker )
72
+ cluster = create_cluster (mocker )
71
73
cluster .up ()
72
74
cluster .down ()
73
75
74
76
77
+ def test_cluster_apply_scale_up_scale_down (mocker ):
78
+ mocker .patch ("kubernetes.client.ApisApi.get_api_versions" )
79
+ mocker .patch ("kubernetes.config.load_kube_config" , return_value = "ignore" )
80
+ mock_dynamic_client = mocker .Mock ()
81
+ mocker .patch (
82
+ "kubernetes.dynamic.DynamicClient.resources" , new_callable = mocker .PropertyMock
83
+ )
84
+ mocker .patch (
85
+ "codeflare_sdk.ray.cluster.cluster.Cluster.create_resource" ,
86
+ return_value = "./tests/test_cluster_yamls/ray/default-ray-cluster.yaml" ,
87
+ )
88
+ mocker .patch ("kubernetes.config.load_kube_config" , return_value = "ignore" )
89
+ mocker .patch (
90
+ "kubernetes.client.CustomObjectsApi.get_cluster_custom_object" ,
91
+ return_value = {"spec" : {"domain" : "apps.cluster.awsroute.org" }},
92
+ )
93
+
94
+ # Initialize test
95
+ initial_num_workers = 1
96
+ scaled_up_num_workers = 2
97
+
98
+ # Step 1: Create cluster with initial workers
99
+ cluster = create_cluster (mocker , initial_num_workers )
100
+ patch_cluster_with_dynamic_client (mocker , cluster , mock_dynamic_client )
101
+ mocker .patch (
102
+ "kubernetes.client.CustomObjectsApi.list_namespaced_custom_object" ,
103
+ return_value = get_obj_none ("ray.io" , "v1" , "ns" , "rayclusters" ),
104
+ )
105
+ cluster .apply ()
106
+
107
+ # Step 2: Scale up the cluster
108
+ cluster = create_cluster (mocker , scaled_up_num_workers )
109
+ patch_cluster_with_dynamic_client (mocker , cluster , mock_dynamic_client )
110
+ cluster .apply ()
111
+
112
+ # Step 3: Scale down the cluster
113
+ cluster = create_cluster (mocker , initial_num_workers )
114
+ patch_cluster_with_dynamic_client (mocker , cluster , mock_dynamic_client )
115
+ cluster .apply ()
116
+
117
+ # Tear down
118
+ cluster .down ()
119
+
120
+
121
+ def test_cluster_apply_with_file (mocker ):
122
+ mocker .patch ("kubernetes.client.ApisApi.get_api_versions" )
123
+ mocker .patch ("kubernetes.config.load_kube_config" , return_value = "ignore" )
124
+ mock_dynamic_client = mocker .Mock ()
125
+ mocker .patch ("codeflare_sdk.ray.cluster.cluster.Cluster._throw_for_no_raycluster" )
126
+ mocker .patch (
127
+ "kubernetes.dynamic.DynamicClient.resources" , new_callable = mocker .PropertyMock
128
+ )
129
+ mocker .patch (
130
+ "codeflare_sdk.ray.cluster.cluster.Cluster.create_resource" ,
131
+ return_value = "./tests/test_cluster_yamls/ray/default-ray-cluster.yaml" ,
132
+ )
133
+ mocker .patch ("kubernetes.config.load_kube_config" , return_value = "ignore" )
134
+ mocker .patch (
135
+ "kubernetes.client.CustomObjectsApi.get_cluster_custom_object" ,
136
+ return_value = {"spec" : {"domain" : "apps.cluster.awsroute.org" }},
137
+ )
138
+
139
+ # Step 1: Create cluster with initial workers
140
+ cluster = create_cluster (mocker , 1 , write_to_file = True )
141
+ patch_cluster_with_dynamic_client (mocker , cluster , mock_dynamic_client )
142
+ mocker .patch (
143
+ "kubernetes.client.CustomObjectsApi.list_namespaced_custom_object" ,
144
+ return_value = get_obj_none ("ray.io" , "v1" , "ns" , "rayclusters" ),
145
+ )
146
+ cluster .apply ()
147
+ # Tear down
148
+ cluster .down ()
149
+
150
+
151
+ def test_cluster_apply_with_appwrapper (mocker ):
152
+ # Mock Kubernetes client and dynamic client methods
153
+ mocker .patch ("kubernetes.client.ApisApi.get_api_versions" )
154
+ mocker .patch ("kubernetes.config.load_kube_config" , return_value = "ignore" )
155
+ mocker .patch (
156
+ "codeflare_sdk.ray.cluster.cluster._check_aw_exists" ,
157
+ return_value = True ,
158
+ )
159
+ mock_dynamic_client = mocker .Mock ()
160
+ mocker .patch ("codeflare_sdk.ray.cluster.cluster.Cluster._throw_for_no_raycluster" )
161
+ mocker .patch (
162
+ "kubernetes.dynamic.DynamicClient.resources" , new_callable = mocker .PropertyMock
163
+ )
164
+ mocker .patch (
165
+ "codeflare_sdk.ray.cluster.cluster.Cluster.create_resource" ,
166
+ return_value = "./tests/test_cluster_yamls/ray/default-ray-cluster.yaml" ,
167
+ )
168
+ mocker .patch ("kubernetes.config.load_kube_config" , return_value = "ignore" )
169
+
170
+ # Create a cluster configuration with appwrapper set to False
171
+ cluster = create_cluster (mocker , 1 , write_to_file = False )
172
+ patch_cluster_with_dynamic_client (mocker , cluster , mock_dynamic_client )
173
+
174
+ # Mock listing RayCluster to simulate it doesn't exist
175
+ mocker .patch (
176
+ "kubernetes.client.CustomObjectsApi.list_namespaced_custom_object" ,
177
+ return_value = get_obj_none ("ray.io" , "v1" , "ns" , "rayclusters" ),
178
+ )
179
+ # Call the apply method
180
+ cluster .apply ()
181
+
182
+ # Assertions
183
+ print ("Cluster applied without AppWrapper." )
184
+
185
+
186
+ def test_cluster_apply_without_appwrapper_write_to_file (mocker ):
187
+ # Mock Kubernetes client and dynamic client methods
188
+ mocker .patch ("kubernetes.client.ApisApi.get_api_versions" )
189
+ mocker .patch ("kubernetes.config.load_kube_config" , return_value = "ignore" )
190
+ mocker .patch (
191
+ "codeflare_sdk.ray.cluster.cluster._check_aw_exists" ,
192
+ return_value = True ,
193
+ )
194
+ mock_dynamic_client = mocker .Mock ()
195
+ mocker .patch ("codeflare_sdk.ray.cluster.cluster.Cluster._throw_for_no_raycluster" )
196
+ mocker .patch (
197
+ "kubernetes.dynamic.DynamicClient.resources" , new_callable = mocker .PropertyMock
198
+ )
199
+ mocker .patch (
200
+ "codeflare_sdk.ray.cluster.cluster.Cluster.create_resource" ,
201
+ return_value = "./tests/test_cluster_yamls/ray/default-ray-cluster.yaml" ,
202
+ )
203
+ mocker .patch ("kubernetes.config.load_kube_config" , return_value = "ignore" )
204
+
205
+ # Create a cluster configuration with appwrapper set to False
206
+ cluster = create_cluster (mocker , 1 , write_to_file = True )
207
+ patch_cluster_with_dynamic_client (mocker , cluster , mock_dynamic_client )
208
+ cluster .config .appwrapper = False
209
+
210
+ # Mock listing RayCluster to simulate it doesn't exist
211
+ mocker .patch (
212
+ "kubernetes.client.CustomObjectsApi.list_namespaced_custom_object" ,
213
+ return_value = get_obj_none ("ray.io" , "v1" , "ns" , "rayclusters" ),
214
+ )
215
+ # Call the apply method
216
+ cluster .apply ()
217
+
218
+ # Assertions
219
+ print ("Cluster applied without AppWrapper." )
220
+
221
+
222
+ def test_cluster_apply_without_appwrapper (mocker ):
223
+ # Mock Kubernetes client and dynamic client methods
224
+ mocker .patch ("kubernetes.client.ApisApi.get_api_versions" )
225
+ mocker .patch ("kubernetes.config.load_kube_config" , return_value = "ignore" )
226
+ mock_dynamic_client = mocker .Mock ()
227
+ mocker .patch ("codeflare_sdk.ray.cluster.cluster.Cluster._throw_for_no_raycluster" )
228
+ mocker .patch (
229
+ "kubernetes.dynamic.DynamicClient.resources" , new_callable = mocker .PropertyMock
230
+ )
231
+ mocker .patch (
232
+ "codeflare_sdk.ray.cluster.cluster.Cluster.create_resource" ,
233
+ return_value = "./tests/test_cluster_yamls/ray/default-ray-cluster.yaml" ,
234
+ )
235
+ mocker .patch ("kubernetes.config.load_kube_config" , return_value = "ignore" )
236
+
237
+ # Create a cluster configuration with appwrapper set to False
238
+ cluster = create_cluster (mocker , 1 , write_to_file = False )
239
+ cluster .config .appwrapper = None
240
+ patch_cluster_with_dynamic_client (mocker , cluster , mock_dynamic_client )
241
+
242
+ # Mock listing RayCluster to simulate it doesn't exist
243
+ mocker .patch (
244
+ "kubernetes.client.CustomObjectsApi.list_namespaced_custom_object" ,
245
+ return_value = get_obj_none ("ray.io" , "v1" , "ns" , "rayclusters" ),
246
+ )
247
+
248
+ # Call the apply method
249
+ cluster .apply ()
250
+
251
+ # Assertions
252
+ print ("Cluster applied without AppWrapper." )
253
+
254
+
75
255
def test_cluster_up_down_no_mcad (mocker ):
76
256
mocker .patch ("codeflare_sdk.ray.cluster.cluster.Cluster._throw_for_no_raycluster" )
77
257
mocker .patch ("kubernetes.config.load_kube_config" , return_value = "ignore" )
@@ -98,7 +278,7 @@ def test_cluster_up_down_no_mcad(mocker):
98
278
"kubernetes.client.CustomObjectsApi.list_cluster_custom_object" ,
99
279
return_value = {"items" : []},
100
280
)
101
- config = createClusterConfig ()
281
+ config = create_cluster_config ()
102
282
config .name = "unit-test-cluster-ray"
103
283
config .appwrapper = False
104
284
cluster = Cluster (config )
@@ -117,7 +297,7 @@ def test_cluster_uris(mocker):
117
297
"kubernetes.client.CustomObjectsApi.list_namespaced_custom_object" ,
118
298
return_value = get_local_queue ("kueue.x-k8s.io" , "v1beta1" , "ns" , "localqueues" ),
119
299
)
120
- cluster = cluster = createClusterWithConfig (mocker )
300
+ cluster = create_cluster (mocker )
121
301
mocker .patch (
122
302
"kubernetes.client.NetworkingV1Api.list_namespaced_ingress" ,
123
303
return_value = ingress_retrieval (
@@ -147,6 +327,52 @@ def test_cluster_uris(mocker):
147
327
== "Dashboard not available yet, have you run cluster.up()?"
148
328
)
149
329
330
+ mocker .patch (
331
+ "codeflare_sdk.ray.cluster.cluster._is_openshift_cluster" , return_value = True
332
+ )
333
+ mocker .patch (
334
+ "kubernetes.client.CustomObjectsApi.list_namespaced_custom_object" ,
335
+ return_value = {
336
+ "items" : [
337
+ {
338
+ "metadata" : {
339
+ "name" : "ray-dashboard-unit-test-cluster" ,
340
+ },
341
+ "spec" : {
342
+ "host" : "ray-dashboard-unit-test-cluster-ns.apps.cluster.awsroute.org" ,
343
+ "tls" : {}, # Indicating HTTPS
344
+ },
345
+ }
346
+ ]
347
+ },
348
+ )
349
+ cluster = create_cluster (mocker )
350
+ assert (
351
+ cluster .cluster_dashboard_uri ()
352
+ == "http://ray-dashboard-unit-test-cluster-ns.apps.cluster.awsroute.org"
353
+ )
354
+ mocker .patch (
355
+ "kubernetes.client.CustomObjectsApi.list_namespaced_custom_object" ,
356
+ return_value = {
357
+ "items" : [
358
+ {
359
+ "metadata" : {
360
+ "name" : "ray-dashboard-unit-test-cluster" ,
361
+ },
362
+ "spec" : {
363
+ "host" : "ray-dashboard-unit-test-cluster-ns.apps.cluster.awsroute.org" ,
364
+ "tls" : {"termination" : "passthrough" }, # Indicating HTTPS
365
+ },
366
+ }
367
+ ]
368
+ },
369
+ )
370
+ cluster = create_cluster (mocker )
371
+ assert (
372
+ cluster .cluster_dashboard_uri ()
373
+ == "https://ray-dashboard-unit-test-cluster-ns.apps.cluster.awsroute.org"
374
+ )
375
+
150
376
151
377
def test_ray_job_wrapping (mocker ):
152
378
import ray
@@ -159,7 +385,7 @@ def ray_addr(self, *args):
159
385
"kubernetes.client.CustomObjectsApi.list_namespaced_custom_object" ,
160
386
return_value = get_local_queue ("kueue.x-k8s.io" , "v1beta1" , "ns" , "localqueues" ),
161
387
)
162
- cluster = cluster = createClusterWithConfig (mocker )
388
+ cluster = create_cluster (mocker )
163
389
mocker .patch (
164
390
"ray.job_submission.JobSubmissionClient._check_connection_and_version_with_url" ,
165
391
return_value = "None" ,
0 commit comments