1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15- """
16- Unit tests for AgentSandboxProvider.
17- """
18-
1915from datetime import datetime , timezone
2016from types import SimpleNamespace
2117from unittest .mock import MagicMock
3834from opensandbox_server .services .k8s .agent_sandbox_provider import AgentSandboxProvider
3935from opensandbox_server .services .constants import OPENSANDBOX_EGRESS_TOKEN
4036
41-
4237def _app_config (
4338 shutdown_policy : str = "Delete" ,
4439 service_account : str | None = None ,
@@ -58,24 +53,16 @@ def _app_config(
5853 egress = egress ,
5954 )
6055
61-
6256class TestAgentSandboxProvider :
63- """AgentSandboxProvider unit tests"""
6457
6558 def test_init_sets_crd_constants_correctly (self , mock_k8s_client ):
66- """
67- Test case: Verify CRD constants set correctly
68- """
6959 provider = AgentSandboxProvider (mock_k8s_client )
7060
7161 assert provider .group == "agents.x-k8s.io"
7262 assert provider .version == "v1alpha1"
7363 assert provider .plural == "sandboxes"
7464
7565 def test_create_workload_builds_correct_manifest_init_mode (self , mock_k8s_client ):
76- """
77- Test case: Verify created manifest structure with init mode
78- """
7966 provider = AgentSandboxProvider (
8067 mock_k8s_client ,
8168 _app_config (shutdown_policy = "Delete" , service_account = "agent-sa" ),
@@ -205,9 +192,6 @@ def test_create_workload_rejects_platform_conflict_with_template_node_affinity(
205192 )
206193
207194 def test_create_workload_sanitizes_resource_name (self , mock_k8s_client ):
208- """
209- Test case: Ensure sandbox names are DNS-1035 compliant when IDs start with digits
210- """
211195 provider = AgentSandboxProvider (mock_k8s_client )
212196 mock_k8s_client .create_custom_object .return_value = {
213197 "metadata" : {"name" : "sandbox-1234" , "uid" : "test-uid" }
@@ -232,9 +216,6 @@ def test_create_workload_sanitizes_resource_name(self, mock_k8s_client):
232216 assert body ["metadata" ]["name" ] == "sandbox-1234"
233217
234218 def test_resource_name_uses_hash_when_id_has_no_alnum (self , mock_k8s_client ):
235- """
236- Test case: Ensure symbol-only sandbox ids do not collapse to the same name
237- """
238219 provider = AgentSandboxProvider (mock_k8s_client )
239220
240221 first = provider ._resource_name ("!!!" )
@@ -245,9 +226,6 @@ def test_resource_name_uses_hash_when_id_has_no_alnum(self, mock_k8s_client):
245226 assert first != second
246227
247228 def test_get_workload_returns_none_on_404 (self , mock_k8s_client ):
248- """
249- Test case: Verify None returned when not found
250- """
251229 provider = AgentSandboxProvider (mock_k8s_client )
252230 mock_k8s_client .get_custom_object .return_value = None
253231
@@ -256,9 +234,6 @@ def test_get_workload_returns_none_on_404(self, mock_k8s_client):
256234 assert result is None
257235
258236 def test_get_workload_prefers_sanitized_name (self , mock_k8s_client ):
259- """
260- Test case: Ensure DNS-1035 resource name is tried before raw id
261- """
262237 provider = AgentSandboxProvider (mock_k8s_client )
263238 mock_k8s_client .get_custom_object .side_effect = [
264239 None ,
@@ -272,9 +247,6 @@ def test_get_workload_prefers_sanitized_name(self, mock_k8s_client):
272247 assert mock_k8s_client .get_custom_object .call_args_list [1 ].kwargs ["name" ] == "1234"
273248
274249 def test_get_workload_falls_back_to_legacy_name (self , mock_k8s_client ):
275- """
276- Test case: Verify legacy sandbox-<id> name is used when primary lookup returns None
277- """
278250 provider = AgentSandboxProvider (mock_k8s_client )
279251 mock_k8s_client .get_custom_object .side_effect = [
280252 None ,
@@ -288,9 +260,6 @@ def test_get_workload_falls_back_to_legacy_name(self, mock_k8s_client):
288260 assert mock_k8s_client .get_custom_object .call_args_list [1 ].kwargs ["name" ] == "sandbox-test-id"
289261
290262 def test_get_workload_reraises_non_404_exceptions (self , mock_k8s_client ):
291- """
292- Test case: Verify non-404 exceptions are re-raised
293- """
294263 provider = AgentSandboxProvider (mock_k8s_client )
295264 mock_k8s_client .get_custom_object .side_effect = ApiException (status = 500 )
296265
@@ -300,9 +269,6 @@ def test_get_workload_reraises_non_404_exceptions(self, mock_k8s_client):
300269 assert exc_info .value .status == 500
301270
302271 def test_get_workload_prefers_informer_cache (self , mock_k8s_client ):
303- """
304- Test case: get_workload calls k8s_client.get_custom_object and returns result
305- """
306272 cached = {"metadata" : {"name" : "test-id" }}
307273 mock_k8s_client .get_custom_object .return_value = cached
308274
@@ -314,9 +280,6 @@ def test_get_workload_prefers_informer_cache(self, mock_k8s_client):
314280 mock_k8s_client .get_custom_object .assert_called ()
315281
316282 def test_create_workload_updates_informer_cache (self , mock_k8s_client ):
317- """
318- Test case: create_workload returns name and uid from created resource
319- """
320283 created_body = {"metadata" : {"name" : "test-id" , "uid" : "test-uid" }}
321284 mock_k8s_client .create_custom_object .return_value = created_body
322285
@@ -339,9 +302,6 @@ def test_create_workload_updates_informer_cache(self, mock_k8s_client):
339302 assert result == {"name" : "test-id" , "uid" : "test-uid" }
340303
341304 def test_update_expiration_patches_spec (self , mock_k8s_client ):
342- """
343- Test case: Verify expiration time update
344- """
345305 provider = AgentSandboxProvider (mock_k8s_client )
346306 mock_k8s_client .get_custom_object .return_value = {"metadata" : {"name" : "sandbox-test-id" }}
347307
@@ -354,9 +314,6 @@ def test_update_expiration_patches_spec(self, mock_k8s_client):
354314 }
355315
356316 def test_get_expiration_parses_z_suffix (self ):
357- """
358- Test case: Verify handling time with Z suffix
359- """
360317 provider = AgentSandboxProvider (MagicMock ())
361318 workload = {"spec" : {"shutdownTime" : "2025-12-31T10:00:00Z" }}
362319
@@ -365,9 +322,6 @@ def test_get_expiration_parses_z_suffix(self):
365322 assert result == datetime (2025 , 12 , 31 , 10 , 0 , 0 , tzinfo = timezone .utc )
366323
367324 def test_get_status_ready_condition_true (self ):
368- """
369- Test case: Verify Ready True is Running
370- """
371325 provider = AgentSandboxProvider (MagicMock ())
372326 workload = {
373327 "status" : {
@@ -391,9 +345,6 @@ def test_get_status_ready_condition_true(self):
391345 assert result ["message" ] == "Ready"
392346
393347 def test_get_status_expired_condition (self ):
394- """
395- Test case: Verify SandboxExpired reason maps to Terminated
396- """
397348 provider = AgentSandboxProvider (MagicMock ())
398349 workload = {
399350 "status" : {
@@ -416,9 +367,6 @@ def test_get_status_expired_condition(self):
416367 assert result ["reason" ] == "SandboxExpired"
417368
418369 def test_get_status_falls_back_to_pod_state (self , mock_k8s_client ):
419- """
420- Test case: Verify status fallback uses pod selector state (Running + IP = Running)
421- """
422370 provider = AgentSandboxProvider (mock_k8s_client )
423371 mock_k8s_client .list_pods .return_value = [
424372 SimpleNamespace (
@@ -436,9 +384,6 @@ def test_get_status_falls_back_to_pod_state(self, mock_k8s_client):
436384 assert result ["reason" ] == "POD_READY"
437385
438386 def test_get_status_falls_back_to_allocated_when_ip_assigned_not_running (self , mock_k8s_client ):
439- """
440- Test case: Verify Allocated state when Pod has IP but is not Running yet
441- """
442387 provider = AgentSandboxProvider (mock_k8s_client )
443388 mock_k8s_client .list_pods .return_value = [
444389 SimpleNamespace (
@@ -597,9 +542,6 @@ def test_get_status_keeps_pending_for_mixed_capacity_and_affinity_message(self,
597542 assert result ["reason" ] in {"POD_SCHEDULED" , "POD_PENDING" }
598543
599544 def test_get_endpoint_info_prefers_running_pod (self , mock_k8s_client ):
600- """
601- Test case: Verify endpoint uses running pod IP
602- """
603545 provider = AgentSandboxProvider (mock_k8s_client )
604546 mock_k8s_client .list_pods .return_value = [
605547 SimpleNamespace (
@@ -617,9 +559,6 @@ def test_get_endpoint_info_prefers_running_pod(self, mock_k8s_client):
617559 assert endpoint .headers is None
618560
619561 def test_get_endpoint_info_falls_back_to_service_fqdn (self , mock_k8s_client ):
620- """
621- Test case: Verify endpoint falls back to serviceFQDN on pod lookup failure
622- """
623562 provider = AgentSandboxProvider (mock_k8s_client )
624563 mock_k8s_client .list_pods .side_effect = Exception ("boom" )
625564 workload = {
@@ -632,14 +571,10 @@ def test_get_endpoint_info_falls_back_to_service_fqdn(self, mock_k8s_client):
632571 assert endpoint .endpoint == "svc.example.com:9000"
633572 assert endpoint .headers is None
634573
635-
636574class TestAgentSandboxProviderExecdInit :
637575 """AgentSandboxProvider execd init container resource tests"""
638576
639577 def test_init_container_has_no_resources_when_not_configured (self , mock_k8s_client ):
640- """
641- Test case: Verify init container has no resources when execd_init_resources is not set
642- """
643578 provider = AgentSandboxProvider (mock_k8s_client )
644579 mock_k8s_client .create_custom_object .return_value = {
645580 "metadata" : {"name" : "test-id" , "uid" : "test-uid" }
@@ -663,9 +598,6 @@ def test_init_container_has_no_resources_when_not_configured(self, mock_k8s_clie
663598 assert "resources" not in init_containers [0 ]
664599
665600 def test_init_container_has_resources_when_configured (self , mock_k8s_client ):
666- """
667- Test case: Verify init container applies resources when execd_init_resources is set
668- """
669601 provider = AgentSandboxProvider (
670602 mock_k8s_client ,
671603 _app_config (execd_init_resources = ExecdInitResources (
@@ -694,14 +626,10 @@ def test_init_container_has_resources_when_configured(self, mock_k8s_client):
694626 assert init_containers [0 ]["resources" ]["limits" ] == {"cpu" : "100m" , "memory" : "128Mi" }
695627 assert init_containers [0 ]["resources" ]["requests" ] == {"cpu" : "50m" , "memory" : "64Mi" }
696628
697-
698629class TestAgentSandboxProviderEgress :
699630 """AgentSandboxProvider egress sidecar tests"""
700631
701632 def test_create_workload_without_network_policy_no_sidecar (self , mock_k8s_client ):
702- """
703- Test case: Verify no sidecar is added when network_policy is None
704- """
705633 provider = AgentSandboxProvider (mock_k8s_client )
706634 mock_k8s_client .create_custom_object .return_value = {
707635 "metadata" : {"name" : "test-id" , "uid" : "test-uid" }
@@ -734,9 +662,6 @@ def test_create_workload_without_network_policy_no_sidecar(self, mock_k8s_client
734662 assert "securityContext" not in pod_spec or "sysctls" not in pod_spec .get ("securityContext" , {})
735663
736664 def test_create_workload_with_network_policy_adds_sidecar (self , mock_k8s_client ):
737- """
738- Test case: Verify egress sidecar is added when network_policy is provided
739- """
740665 provider = AgentSandboxProvider (
741666 mock_k8s_client ,
742667 _app_config (egress = EgressConfig ()),
@@ -932,9 +857,6 @@ def test_create_workload_with_egress_skips_ipv6_disable_when_not_configured(self
932857 assert "/proc/sys/net/ipv6/conf/all/disable_ipv6" not in execd_init ["args" ][0 ]
933858
934859 def test_create_workload_with_network_policy_drops_net_admin_from_main_container (self , mock_k8s_client ):
935- """
936- Test case: Verify main container drops NET_ADMIN when network_policy is enabled
937- """
938860 provider = AgentSandboxProvider (mock_k8s_client )
939861 mock_k8s_client .create_custom_object .return_value = {
940862 "metadata" : {"name" : "test-id" , "uid" : "test-uid" }
@@ -975,9 +897,6 @@ def test_create_workload_with_network_policy_drops_net_admin_from_main_container
975897 assert "NET_ADMIN" in main_container ["securityContext" ]["capabilities" ]["drop" ]
976898
977899 def test_create_workload_without_egress_image_no_sidecar (self , mock_k8s_client ):
978- """
979- Test case: Verify no sidecar is added when egress_image is None even if network_policy exists
980- """
981900 provider = AgentSandboxProvider (mock_k8s_client )
982901 mock_k8s_client .create_custom_object .return_value = {
983902 "metadata" : {"name" : "test-id" , "uid" : "test-uid" }
@@ -1012,9 +931,6 @@ def test_create_workload_without_egress_image_no_sidecar(self, mock_k8s_client):
1012931 assert containers [0 ]["name" ] == "sandbox"
1013932
1014933 def test_egress_sidecar_contains_network_policy_in_env (self , mock_k8s_client ):
1015- """
1016- Test case: Verify sidecar environment variable contains serialized network policy
1017- """
1018934 provider = AgentSandboxProvider (mock_k8s_client )
1019935 mock_k8s_client .create_custom_object .return_value = {
1020936 "metadata" : {"name" : "test-id" , "uid" : "test-uid" }
@@ -1062,9 +978,6 @@ def test_egress_sidecar_contains_network_policy_in_env(self, mock_k8s_client):
1062978 assert policy_json ["egress" ][0 ]["target" ] == "pypi.org"
1063979
1064980 def test_main_container_no_security_context_without_network_policy (self , mock_k8s_client ):
1065- """
1066- Test case: Verify main container has no securityContext when network_policy is None
1067- """
1068981 provider = AgentSandboxProvider (mock_k8s_client )
1069982 mock_k8s_client .create_custom_object .return_value = {
1070983 "metadata" : {"name" : "test-id" , "uid" : "test-uid" }
0 commit comments