Skip to content

Commit 70fe5b2

Browse files
committed
task(RHOAIENG-30722):Update code coverage
1 parent b52e9bc commit 70fe5b2

File tree

1 file changed

+185
-1
lines changed

1 file changed

+185
-1
lines changed

src/codeflare_sdk/ray/cluster/test_cluster.py

Lines changed: 185 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,11 @@
3737
from unittest.mock import MagicMock
3838
from kubernetes import client
3939
import yaml
40+
import pytest
4041
import filecmp
4142
import os
43+
import ray
44+
import tempfile
4245

4346
parent = Path(__file__).resolve().parents[4] # project directory
4447
expected_clusters_dir = f"{parent}/tests/test_cluster_yamls"
@@ -377,7 +380,6 @@ def test_cluster_uris(mocker):
377380

378381

379382
def test_ray_job_wrapping(mocker):
380-
import ray
381383

382384
def ray_addr(self, *args):
383385
return self._address
@@ -770,6 +772,188 @@ def custom_side_effect(group, version, namespace, plural, **kwargs):
770772
assert result.dashboard == rc_dashboard
771773

772774

775+
def test_throw_for_no_raycluster_crd_errors(mocker):
776+
"""Test RayCluster CRD error handling"""
777+
from kubernetes.client.rest import ApiException
778+
779+
mocker.patch("kubernetes.config.load_kube_config", return_value="ignore")
780+
781+
# Test 404 error - CRD not found
782+
mock_api_404 = MagicMock()
783+
mock_api_404.list_namespaced_custom_object.side_effect = ApiException(status=404)
784+
mocker.patch("kubernetes.client.CustomObjectsApi", return_value=mock_api_404)
785+
786+
cluster = create_cluster(mocker)
787+
with pytest.raises(
788+
RuntimeError, match="RayCluster CustomResourceDefinition unavailable"
789+
):
790+
cluster._throw_for_no_raycluster()
791+
792+
# Test other API error
793+
mock_api_500 = MagicMock()
794+
mock_api_500.list_namespaced_custom_object.side_effect = ApiException(status=500)
795+
mocker.patch("kubernetes.client.CustomObjectsApi", return_value=mock_api_500)
796+
797+
cluster2 = create_cluster(mocker)
798+
with pytest.raises(
799+
RuntimeError, match="Failed to get RayCluster CustomResourceDefinition"
800+
):
801+
cluster2._throw_for_no_raycluster()
802+
803+
804+
def test_cluster_apply_attribute_error_handling(mocker):
805+
"""Test AttributeError handling when DynamicClient fails"""
806+
mocker.patch("kubernetes.config.load_kube_config", return_value="ignore")
807+
mocker.patch("codeflare_sdk.ray.cluster.cluster.Cluster._throw_for_no_raycluster")
808+
mocker.patch(
809+
"kubernetes.client.CustomObjectsApi.list_namespaced_custom_object",
810+
return_value=get_local_queue("kueue.x-k8s.io", "v1beta1", "ns", "localqueues"),
811+
)
812+
813+
# Mock get_dynamic_client to raise AttributeError
814+
def raise_attribute_error():
815+
raise AttributeError("DynamicClient initialization failed")
816+
817+
mocker.patch(
818+
"codeflare_sdk.ray.cluster.cluster.Cluster.get_dynamic_client",
819+
side_effect=raise_attribute_error,
820+
)
821+
822+
cluster = create_cluster(mocker)
823+
824+
with pytest.raises(RuntimeError, match="Failed to initialize DynamicClient"):
825+
cluster.apply()
826+
827+
828+
def test_cluster_namespace_handling(mocker, capsys):
829+
"""Test namespace validation in create_resource"""
830+
mocker.patch("kubernetes.config.load_kube_config", return_value="ignore")
831+
mocker.patch(
832+
"kubernetes.client.CustomObjectsApi.list_namespaced_custom_object",
833+
return_value=get_local_queue("kueue.x-k8s.io", "v1beta1", "ns", "localqueues"),
834+
)
835+
836+
# Test with None namespace that gets set
837+
mocker.patch(
838+
"codeflare_sdk.ray.cluster.cluster.get_current_namespace", return_value=None
839+
)
840+
841+
config = ClusterConfiguration(
842+
name="test-cluster-ns",
843+
namespace=None, # Will trigger namespace check
844+
num_workers=1,
845+
worker_cpu_requests=1,
846+
worker_cpu_limits=1,
847+
worker_memory_requests=2,
848+
worker_memory_limits=2,
849+
)
850+
851+
cluster = Cluster(config)
852+
captured = capsys.readouterr()
853+
# Verify the warning message was printed
854+
assert "Please specify with namespace=<your_current_namespace>" in captured.out
855+
assert cluster.config.namespace is None
856+
857+
858+
def test_component_resources_with_write_to_file(mocker):
859+
"""Test _component_resources_up with write_to_file enabled"""
860+
mocker.patch("kubernetes.config.load_kube_config", return_value="ignore")
861+
mocker.patch(
862+
"kubernetes.client.CustomObjectsApi.list_namespaced_custom_object",
863+
return_value=get_local_queue("kueue.x-k8s.io", "v1beta1", "ns", "localqueues"),
864+
)
865+
866+
# Mock the _create_resources function
867+
mocker.patch("codeflare_sdk.ray.cluster.cluster._create_resources")
868+
869+
# Create cluster with write_to_file=True (without appwrapper)
870+
config = ClusterConfiguration(
871+
name="test-cluster-component",
872+
namespace="ns",
873+
num_workers=1,
874+
worker_cpu_requests=1,
875+
worker_cpu_limits=1,
876+
worker_memory_requests=2,
877+
worker_memory_limits=2,
878+
write_to_file=True,
879+
appwrapper=False,
880+
)
881+
882+
cluster = Cluster(config)
883+
884+
# Mock file reading and test _component_resources_up
885+
886+
with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
887+
f.write("apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: test")
888+
temp_file = f.name
889+
890+
try:
891+
mock_api = MagicMock()
892+
cluster.resource_yaml = temp_file
893+
cluster._component_resources_up("ns", mock_api)
894+
# If we got here without error, the write_to_file path was executed
895+
assert True
896+
finally:
897+
os.unlink(temp_file)
898+
899+
900+
def test_get_cluster_status_functions(mocker):
901+
"""Test _app_wrapper_status and _ray_cluster_status functions"""
902+
from codeflare_sdk.ray.cluster.cluster import (
903+
_app_wrapper_status,
904+
_ray_cluster_status,
905+
)
906+
907+
mocker.patch("kubernetes.config.load_kube_config", return_value="ignore")
908+
mocker.patch("codeflare_sdk.ray.cluster.cluster.config_check")
909+
910+
# Test _app_wrapper_status when cluster not found
911+
mocker.patch(
912+
"kubernetes.client.CustomObjectsApi.list_namespaced_custom_object",
913+
return_value={"items": []},
914+
)
915+
result = _app_wrapper_status("non-existent-cluster", "ns")
916+
assert result is None
917+
918+
# Test _ray_cluster_status when cluster not found
919+
mocker.patch(
920+
"kubernetes.client.CustomObjectsApi.list_namespaced_custom_object",
921+
return_value={"items": []},
922+
)
923+
result = _ray_cluster_status("non-existent-cluster", "ns")
924+
assert result is None
925+
926+
927+
def test_cluster_namespace_type_error(mocker):
928+
"""Test TypeError when namespace is not a string"""
929+
mocker.patch("kubernetes.config.load_kube_config", return_value="ignore")
930+
mocker.patch(
931+
"kubernetes.client.CustomObjectsApi.list_namespaced_custom_object",
932+
return_value=get_local_queue("kueue.x-k8s.io", "v1beta1", "ns", "localqueues"),
933+
)
934+
935+
# Mock get_current_namespace to return a non-string value (e.g., int)
936+
mocker.patch(
937+
"codeflare_sdk.ray.cluster.cluster.get_current_namespace", return_value=12345
938+
)
939+
940+
config = ClusterConfiguration(
941+
name="test-cluster-type-error",
942+
namespace=None, # Will trigger namespace check
943+
num_workers=1,
944+
worker_cpu_requests=1,
945+
worker_cpu_limits=1,
946+
worker_memory_requests=2,
947+
worker_memory_limits=2,
948+
)
949+
950+
# This should raise TypeError because get_current_namespace returns int
951+
with pytest.raises(
952+
TypeError, match="Namespace 12345 is of type.*Check your Kubernetes Authentication"
953+
):
954+
Cluster(config)
955+
956+
773957
# Make sure to always keep this function last
774958
def test_cleanup():
775959
os.remove(f"{aw_dir}test-all-params.yaml")

0 commit comments

Comments
 (0)