@@ -542,3 +542,108 @@ def test_telemetry_emitter_without_resource_arn(
542542 args = mock_send_telemetry_request .call_args .args
543543 extra_str = str (args [5 ])
544544 self .assertNotIn ("x-resourceArn" , extra_str )
545+
546+ @patch ("sagemaker.core.telemetry.telemetry_logging._send_telemetry_request" )
547+ @patch ("sagemaker.core.telemetry.telemetry_logging.resolve_value_from_config" )
548+ def test_telemetry_emitter_appends_nova_sub_feature (
549+ self , mock_resolve_config , mock_send_telemetry_request
550+ ):
551+ """Test that MODEL_CUSTOMIZATION_NOVA (19) is appended when instance reports Nova model."""
552+ mock_resolve_config .return_value = False
553+
554+ class NovaModelMock :
555+ def __init__ (self ):
556+ self .sagemaker_session = MOCK_SESSION
557+
558+ def _is_nova_model_for_telemetry (self ):
559+ return True
560+
561+ @_telemetry_emitter (Feature .MODEL_CUSTOMIZATION , "NovaModelMock.train" )
562+ def train (self ):
563+ pass
564+
565+ NovaModelMock ().train ()
566+
567+ args = mock_send_telemetry_request .call_args .args
568+ feature_list = args [1 ]
569+ self .assertIn (15 , feature_list ) # MODEL_CUSTOMIZATION
570+ self .assertIn (19 , feature_list ) # MODEL_CUSTOMIZATION_NOVA
571+ self .assertNotIn (20 , feature_list ) # MODEL_CUSTOMIZATION_OSS should NOT be present
572+
573+ @patch ("sagemaker.core.telemetry.telemetry_logging._send_telemetry_request" )
574+ @patch ("sagemaker.core.telemetry.telemetry_logging.resolve_value_from_config" )
575+ def test_telemetry_emitter_appends_oss_sub_feature (
576+ self , mock_resolve_config , mock_send_telemetry_request
577+ ):
578+ """Test that MODEL_CUSTOMIZATION_OSS (20) is appended when instance reports non-Nova model."""
579+ mock_resolve_config .return_value = False
580+
581+ class OssModelMock :
582+ def __init__ (self ):
583+ self .sagemaker_session = MOCK_SESSION
584+
585+ def _is_nova_model_for_telemetry (self ):
586+ return False
587+
588+ @_telemetry_emitter (Feature .MODEL_CUSTOMIZATION , "OssModelMock.train" )
589+ def train (self ):
590+ pass
591+
592+ OssModelMock ().train ()
593+
594+ args = mock_send_telemetry_request .call_args .args
595+ feature_list = args [1 ]
596+ self .assertIn (15 , feature_list ) # MODEL_CUSTOMIZATION
597+ self .assertIn (20 , feature_list ) # MODEL_CUSTOMIZATION_OSS
598+ self .assertNotIn (19 , feature_list ) # MODEL_CUSTOMIZATION_NOVA should NOT be present
599+
600+ @patch ("sagemaker.core.telemetry.telemetry_logging._send_telemetry_request" )
601+ @patch ("sagemaker.core.telemetry.telemetry_logging.resolve_value_from_config" )
602+ def test_telemetry_emitter_no_sub_feature_without_detection_method (
603+ self , mock_resolve_config , mock_send_telemetry_request
604+ ):
605+ """Test that no NOVA/OSS sub-feature is appended when instance lacks detection method."""
606+ mock_resolve_config .return_value = False
607+
608+ class NoDetectionMock :
609+ def __init__ (self ):
610+ self .sagemaker_session = MOCK_SESSION
611+
612+ @_telemetry_emitter (Feature .MODEL_CUSTOMIZATION , "NoDetectionMock.do_work" )
613+ def do_work (self ):
614+ pass
615+
616+ NoDetectionMock ().do_work ()
617+
618+ args = mock_send_telemetry_request .call_args .args
619+ feature_list = args [1 ]
620+ self .assertIn (15 , feature_list ) # MODEL_CUSTOMIZATION
621+ self .assertNotIn (19 , feature_list ) # No NOVA
622+ self .assertNotIn (20 , feature_list ) # No OSS
623+
624+ @patch ("sagemaker.core.telemetry.telemetry_logging._send_telemetry_request" )
625+ @patch ("sagemaker.core.telemetry.telemetry_logging.resolve_value_from_config" )
626+ def test_telemetry_emitter_handles_detection_method_exception (
627+ self , mock_resolve_config , mock_send_telemetry_request
628+ ):
629+ """Test that telemetry still works when _is_nova_model_for_telemetry raises an exception."""
630+ mock_resolve_config .return_value = False
631+
632+ class BrokenDetectionMock :
633+ def __init__ (self ):
634+ self .sagemaker_session = MOCK_SESSION
635+
636+ def _is_nova_model_for_telemetry (self ):
637+ raise RuntimeError ("detection failed" )
638+
639+ @_telemetry_emitter (Feature .MODEL_CUSTOMIZATION , "BrokenDetectionMock.train" )
640+ def train (self ):
641+ pass
642+
643+ BrokenDetectionMock ().train ()
644+
645+ args = mock_send_telemetry_request .call_args .args
646+ feature_list = args [1 ]
647+ self .assertIn (15 , feature_list ) # MODEL_CUSTOMIZATION still present
648+ self .assertNotIn (19 , feature_list ) # No NOVA (detection failed gracefully)
649+ self .assertNotIn (20 , feature_list ) # No OSS
0 commit comments