@@ -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"
@@ -649,3 +652,92 @@ func TestSandboxExpiry(t *testing.T) {
649652 })
650653 }
651654}
655+
656+ func TestSandboxCreationLatencyMetric (t * testing.T ) {
657+ sandboxName := "sandbox-name"
658+ sandboxNs := "sandbox-ns"
659+ sb := & sandboxv1alpha1.Sandbox {}
660+ sb .Name = sandboxName
661+ sb .Namespace = sandboxNs
662+ sb .Generation = 1
663+ sb .CreationTimestamp = metav1 .NewTime (time .Now ())
664+ sb .Spec = sandboxv1alpha1.SandboxSpec {
665+ PodTemplate : sandboxv1alpha1.PodTemplate {
666+ Spec : corev1.PodSpec {
667+ Containers : []corev1.Container {
668+ {
669+ Name : "test-container" ,
670+ },
671+ },
672+ },
673+ },
674+ }
675+
676+ r := SandboxReconciler {
677+ Client : newFakeClient (sb ),
678+ Scheme : Scheme ,
679+ }
680+
681+ _ , err := r .Reconcile (t .Context (), ctrl.Request {
682+ NamespacedName : types.NamespacedName {
683+ Name : sandboxName ,
684+ Namespace : sandboxNs ,
685+ },
686+ })
687+ require .NoError (t , err )
688+
689+ // get pod and mark it ready
690+ pod := & corev1.Pod {}
691+ require .NoError (t , r .Get (t .Context (), types.NamespacedName {Name : sandboxName , Namespace : sandboxNs }, pod ))
692+ pod .Status .Phase = corev1 .PodRunning
693+ pod .Status .Conditions = []corev1.PodCondition {
694+ {
695+ Type : corev1 .PodReady ,
696+ Status : corev1 .ConditionTrue ,
697+ },
698+ }
699+ require .NoError (t , r .Status ().Update (t .Context (), pod ))
700+
701+ _ , err = r .Reconcile (t .Context (), ctrl.Request {
702+ NamespacedName : types.NamespacedName {
703+ Name : sandboxName ,
704+ Namespace : sandboxNs ,
705+ },
706+ })
707+ require .NoError (t , err )
708+
709+ // Validate Sandbox status
710+ liveSandbox := & sandboxv1alpha1.Sandbox {}
711+ require .NoError (t , r .Get (t .Context (), types.NamespacedName {Name : sandboxName , Namespace : sandboxNs }, liveSandbox ))
712+ require .True (t , meta .IsStatusConditionTrue (liveSandbox .Status .Conditions , "Ready" ))
713+ require .NotNil (t , liveSandbox .Annotations )
714+ require .Equal (t , "true" , liveSandbox .Annotations [readinessObserved ])
715+
716+ // Check metric
717+ expected := `
718+ # HELP sandbox_creation_latency Time taken from sandbox creation to sandbox ready
719+ # TYPE sandbox_creation_latency histogram
720+ sandbox_creation_latency_bucket{le="1"} 1
721+ sandbox_creation_latency_bucket{le="2"} 1
722+ sandbox_creation_latency_bucket{le="3"} 1
723+ sandbox_creation_latency_bucket{le="5"} 1
724+ sandbox_creation_latency_bucket{le="7"} 1
725+ sandbox_creation_latency_bucket{le="10"} 1
726+ sandbox_creation_latency_bucket{le="15"} 1
727+ sandbox_creation_latency_bucket{le="20"} 1
728+ sandbox_creation_latency_bucket{le="30"} 1
729+ sandbox_creation_latency_bucket{le="45"} 1
730+ sandbox_creation_latency_bucket{le="60"} 1
731+ sandbox_creation_latency_bucket{le="90"} 1
732+ sandbox_creation_latency_bucket{le="120"} 1
733+ sandbox_creation_latency_bucket{le="180"} 1
734+ sandbox_creation_latency_bucket{le="300"} 1
735+ sandbox_creation_latency_bucket{le="+Inf"} 1
736+ sandbox_creation_latency_count 1
737+ `
738+ err = testutil .CollectAndCompare (sandboxCreationLatency , strings .NewReader (expected ), "sandbox_creation_latency" )
739+ // We ignore the error because the sum is not deterministic
740+ if err != nil && ! strings .Contains (err .Error (), "sandbox_creation_latency_sum" ) {
741+ require .NoError (t , err )
742+ }
743+ }
0 commit comments