@@ -969,6 +969,146 @@ func TestRecordCreationLatencyMetric(t *testing.T) {
969969 }
970970}
971971
972+ func TestSandboxClaimCreationMetric (t * testing.T ) {
973+ template := & extensionsv1alpha1.SandboxTemplate {
974+ ObjectMeta : metav1.ObjectMeta {Name : "test-template" , Namespace : "default" },
975+ Spec : extensionsv1alpha1.SandboxTemplateSpec {
976+ PodTemplate : sandboxv1alpha1.PodTemplate {
977+ Spec : corev1.PodSpec {
978+ Containers : []corev1.Container {{Name : "test-container" , Image : "test-image" }},
979+ },
980+ },
981+ },
982+ }
983+
984+ claim := & extensionsv1alpha1.SandboxClaim {
985+ ObjectMeta : metav1.ObjectMeta {Name : "test-claim" , Namespace : "default" , UID : "claim-uid" },
986+ Spec : extensionsv1alpha1.SandboxClaimSpec {TemplateRef : extensionsv1alpha1.SandboxTemplateRef {Name : "test-template" }},
987+ }
988+
989+ t .Run ("Cold Start" , func (t * testing.T ) {
990+ asmetrics .SandboxClaimCreationTotal .Reset ()
991+ scheme := newScheme (t )
992+ client := fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (template , claim ).WithStatusSubresource (claim ).Build ()
993+ reconciler := & SandboxClaimReconciler {
994+ Client : client ,
995+ Scheme : scheme ,
996+ Recorder : record .NewFakeRecorder (10 ),
997+ Tracer : asmetrics .NewNoOp (),
998+ }
999+
1000+ req := reconcile.Request {NamespacedName : types.NamespacedName {Name : claim .Name , Namespace : "default" }}
1001+ _ , err := reconciler .Reconcile (context .Background (), req )
1002+ if err != nil {
1003+ t .Fatalf ("reconcile failed: %v" , err )
1004+ }
1005+
1006+ // Verify metric
1007+ val := testutil .ToFloat64 (asmetrics .SandboxClaimCreationTotal .WithLabelValues ("default" , "test-template" , asmetrics .LaunchTypeCold , "none" , "not_ready" ))
1008+ if val != 1 {
1009+ t .Errorf ("expected metric count 1, got %v" , val )
1010+ }
1011+ })
1012+
1013+ t .Run ("Warm Start" , func (t * testing.T ) {
1014+ asmetrics .SandboxClaimCreationTotal .Reset ()
1015+
1016+ // Create a warm pool pod
1017+ poolNameHash := sandboxcontrollers .NameHash ("test-pool" )
1018+ warmPod := & corev1.Pod {
1019+ ObjectMeta : metav1.ObjectMeta {
1020+ Name : "warm-pod" ,
1021+ Namespace : "default" ,
1022+ Labels : map [string ]string {
1023+ poolLabel : poolNameHash ,
1024+ sandboxTemplateRefHash : sandboxcontrollers .NameHash ("test-template" ),
1025+ },
1026+ OwnerReferences : []metav1.OwnerReference {
1027+ {
1028+ APIVersion : "extensions.agents.x-k8s.io/v1alpha1" ,
1029+ Kind : "SandboxWarmPool" ,
1030+ Name : "test-pool" ,
1031+ UID : "pool-uid" ,
1032+ Controller : ptr .To (true ),
1033+ },
1034+ },
1035+ },
1036+ Status : corev1.PodStatus {Conditions : []corev1.PodCondition {{Type : corev1 .PodReady , Status : corev1 .ConditionTrue }}},
1037+ Spec : corev1.PodSpec {Containers : []corev1.Container {{Name : "c" , Image : "i" }}},
1038+ }
1039+
1040+ scheme := newScheme (t )
1041+ client := fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (template , claim , warmPod ).WithStatusSubresource (claim ).Build ()
1042+ reconciler := & SandboxClaimReconciler {
1043+ Client : client ,
1044+ Scheme : scheme ,
1045+ Recorder : record .NewFakeRecorder (10 ),
1046+ Tracer : asmetrics .NewNoOp (),
1047+ }
1048+
1049+ req := reconcile.Request {NamespacedName : types.NamespacedName {Name : claim .Name , Namespace : "default" }}
1050+ _ , err := reconciler .Reconcile (context .Background (), req )
1051+ if err != nil {
1052+ t .Fatalf ("reconcile failed: %v" , err )
1053+ }
1054+
1055+ // Verify metric
1056+ val := testutil .ToFloat64 (asmetrics .SandboxClaimCreationTotal .WithLabelValues ("default" , "test-template" , asmetrics .LaunchTypeWarm , "test-pool" , "ready" ))
1057+ if val != 1 {
1058+ t .Errorf ("expected metric count 1, got %v" , val )
1059+ }
1060+ })
1061+
1062+ t .Run ("Warm Start Not Ready" , func (t * testing.T ) {
1063+ asmetrics .SandboxClaimCreationTotal .Reset ()
1064+
1065+ // Create a warm pool pod that is NOT ready
1066+ poolNameHash := sandboxcontrollers .NameHash ("test-pool" )
1067+ warmPod := & corev1.Pod {
1068+ ObjectMeta : metav1.ObjectMeta {
1069+ Name : "warm-pod-not-ready" ,
1070+ Namespace : "default" ,
1071+ Labels : map [string ]string {
1072+ poolLabel : poolNameHash ,
1073+ sandboxTemplateRefHash : sandboxcontrollers .NameHash ("test-template" ),
1074+ },
1075+ OwnerReferences : []metav1.OwnerReference {
1076+ {
1077+ APIVersion : "extensions.agents.x-k8s.io/v1alpha1" ,
1078+ Kind : "SandboxWarmPool" ,
1079+ Name : "test-pool" ,
1080+ UID : "pool-uid" ,
1081+ Controller : ptr .To (true ),
1082+ },
1083+ },
1084+ },
1085+ Status : corev1.PodStatus {Conditions : []corev1.PodCondition {{Type : corev1 .PodReady , Status : corev1 .ConditionFalse }}},
1086+ Spec : corev1.PodSpec {Containers : []corev1.Container {{Name : "c" , Image : "i" }}},
1087+ }
1088+
1089+ scheme := newScheme (t )
1090+ client := fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (template , claim , warmPod ).WithStatusSubresource (claim ).Build ()
1091+ reconciler := & SandboxClaimReconciler {
1092+ Client : client ,
1093+ Scheme : scheme ,
1094+ Recorder : record .NewFakeRecorder (10 ),
1095+ Tracer : asmetrics .NewNoOp (),
1096+ }
1097+
1098+ req := reconcile.Request {NamespacedName : types.NamespacedName {Name : claim .Name , Namespace : "default" }}
1099+ _ , err := reconciler .Reconcile (context .Background (), req )
1100+ if err != nil {
1101+ t .Fatalf ("reconcile failed: %v" , err )
1102+ }
1103+
1104+ // Verify metric
1105+ val := testutil .ToFloat64 (asmetrics .SandboxClaimCreationTotal .WithLabelValues ("default" , "test-template" , asmetrics .LaunchTypeWarm , "test-pool" , "not_ready" ))
1106+ if val != 1 {
1107+ t .Errorf ("expected metric count 1, got %v" , val )
1108+ }
1109+ })
1110+ }
1111+
9721112func newScheme (t * testing.T ) * runtime.Scheme {
9731113 scheme := runtime .NewScheme ()
9741114 if err := sandboxv1alpha1 .AddToScheme (scheme ); err != nil {
0 commit comments