@@ -16,14 +16,17 @@ package controllers
1616
1717import (
1818 "errors"
19+ "strings"
1920 "testing"
2021 "time"
2122
2223 "github.com/google/go-cmp/cmp"
2324 "github.com/google/go-cmp/cmp/cmpopts"
25+ "github.com/prometheus/client_golang/prometheus/testutil"
2426 "github.com/stretchr/testify/require"
2527 corev1 "k8s.io/api/core/v1"
2628 k8serrors "k8s.io/apimachinery/pkg/api/errors"
29+ "k8s.io/apimachinery/pkg/api/meta"
2730 "k8s.io/apimachinery/pkg/api/resource"
2831 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2932 "k8s.io/apimachinery/pkg/runtime"
@@ -846,3 +849,94 @@ func TestSandboxExpiry(t *testing.T) {
846849 })
847850 }
848851}
852+
853+ func TestSandboxCreationLatencyMetric (t * testing.T ) {
854+ sandboxName := "sandbox-name"
855+ sandboxNs := "sandbox-ns"
856+ sb := & sandboxv1alpha1.Sandbox {}
857+ sb .Name = sandboxName
858+ sb .Namespace = sandboxNs
859+ sb .Generation = 1
860+ sb .CreationTimestamp = metav1 .NewTime (time .Now ())
861+ sb .Spec = sandboxv1alpha1.SandboxSpec {
862+ PodTemplate : sandboxv1alpha1.PodTemplate {
863+ Spec : corev1.PodSpec {
864+ Containers : []corev1.Container {
865+ {
866+ Name : "test-container" ,
867+ },
868+ },
869+ },
870+ },
871+ }
872+
873+ r := SandboxReconciler {
874+ Client : newFakeClient (sb ),
875+ Scheme : Scheme ,
876+ }
877+
878+ _ , err := r .Reconcile (t .Context (), ctrl.Request {
879+ NamespacedName : types.NamespacedName {
880+ Name : sandboxName ,
881+ Namespace : sandboxNs ,
882+ },
883+ })
884+ require .NoError (t , err )
885+
886+ // get pod and mark it ready
887+ pod := & corev1.Pod {}
888+ require .NoError (t , r .Get (t .Context (), types.NamespacedName {Name : sandboxName , Namespace : sandboxNs }, pod ))
889+ pod .Status .Phase = corev1 .PodRunning
890+ pod .Status .Conditions = []corev1.PodCondition {
891+ {
892+ Type : corev1 .PodReady ,
893+ Status : corev1 .ConditionTrue ,
894+ },
895+ }
896+ require .NoError (t , r .Status ().Update (t .Context (), pod ))
897+
898+ _ , err = r .Reconcile (t .Context (), ctrl.Request {
899+ NamespacedName : types.NamespacedName {
900+ Name : sandboxName ,
901+ Namespace : sandboxNs ,
902+ },
903+ })
904+ require .NoError (t , err )
905+
906+ // Validate Sandbox status
907+ liveSandbox := & sandboxv1alpha1.Sandbox {}
908+ require .NoError (t , r .Get (t .Context (), types.NamespacedName {Name : sandboxName , Namespace : sandboxNs }, liveSandbox ))
909+ require .True (t , meta .IsStatusConditionTrue (liveSandbox .Status .Conditions , "Ready" ))
910+ require .NotNil (t , liveSandbox .Annotations )
911+ require .Equal (t , "true" , liveSandbox .Annotations [readinessObserved ])
912+
913+ // Check metric
914+ expected := `
915+ # HELP sandbox_creation_latency Time taken from sandbox creation to sandbox ready in milliseconds
916+ # TYPE sandbox_creation_latency histogram
917+ sandbox_creation_latency_bucket{le="50"} 1
918+
919+ sandbox_creation_latency_bucket{le="100"} 1
920+ sandbox_creation_latency_bucket{le="200"} 1
921+ sandbox_creation_latency_bucket{le="300"} 1
922+ sandbox_creation_latency_bucket{le="500"} 1
923+ sandbox_creation_latency_bucket{le="700"} 1
924+ sandbox_creation_latency_bucket{le="1000"} 1
925+ sandbox_creation_latency_bucket{le="1500"} 1
926+ sandbox_creation_latency_bucket{le="2000"} 1
927+ sandbox_creation_latency_bucket{le="3000"} 1
928+ sandbox_creation_latency_bucket{le="4500"} 1
929+ sandbox_creation_latency_bucket{le="6000"} 1
930+ sandbox_creation_latency_bucket{le="9000"} 1
931+ sandbox_creation_latency_bucket{le="12000"} 1
932+ sandbox_creation_latency_bucket{le="18000"} 1
933+ sandbox_creation_latency_bucket{le="30000"} 1
934+ sandbox_creation_latency_bucket{le="+Inf"} 1
935+ sandbox_creation_latency_count 1
936+ `
937+ err = testutil .CollectAndCompare (sandboxCreationLatency , strings .NewReader (expected ), "sandbox_creation_latency" )
938+ // We ignore the error because the sum is not deterministic
939+ if err != nil && ! strings .Contains (err .Error (), "sandbox_creation_latency_sum" ) {
940+ require .NoError (t , err )
941+ }
942+ }
0 commit comments